Tại sao Line Feed được chuyển đổi thành một ký tự Null bên trong thanh ghi tìm kiếm và trở thành Vận chuyển trở lại trên dòng lệnh?


12

Nếu tôi có văn bản sau:

foo
bar

Tôi trực quan chọn nó và sao chép nó.
Văn bản hiện được lưu trữ trong thanh ghi không tên "và đây là nội dung của nó (đầu ra của :reg "):

""   foo^Jbar^J

Theo biểu đồ này , có vẻ như ^Jlà ký hiệu dấu mũ cho Line Feed.

Nếu tôi muốn sao chép thanh ghi không tên trong thanh aghi bằng cách gõ: :let @a = @"
Đây là nội dung của nó (đầu ra của :reg a):

"a   foo^Jbar^J

Nó không thay đổi.

Nếu bây giờ tôi sao chép nó trong sổ đăng ký tìm kiếm bằng cách gõ :let @/ = @", thì đây là nội dung của nó (đầu ra của :reg /):

"/   foo^@bar^@

Theo biểu đồ trước đó, có vẻ như ^@ký hiệu dấu mũ cho một nhân vật Null.
Tại sao Line Feed tự động được chuyển đổi thành ký tự Null bên trong thanh ghi tìm kiếm (nhưng không phải là athanh ghi)?

Nếu tôi chèn thanh ghi không tên trên dòng lệnh (hoặc bên trong tìm kiếm sau /), bằng cách nhập :<C-R>", đây là những gì được chèn:

:foo^Mbar^M

Một lần nữa, theo biểu đồ cuối cùng, ^Mdường như là ký hiệu dấu mũ cho Vận chuyển trở lại.
Tại sao Line Feed tự động được chuyển đổi thành Vận chuyển trở lại trên dòng lệnh?

Chỉnh sửa :

Thông thường bạn có thể chèn một ký tự điều khiển bằng chữ bằng cách gõ:
<C-V><C-{character in caret notation}>

Ví dụ: bạn có thể chèn một chữ <C-R>bằng cách gõ <C-V><C-R>.
Bạn có thể làm điều đó cho dường như bất kỳ nhân vật điều khiển.
Tuy nhiên, tôi nhận thấy rằng tôi không thể chèn một chữ viết tắt trong một bộ đệm hoặc trên dòng lệnh, bởi vì nếu tôi gõ: <C-V><C-J>nó sẽ chèn ^@, một ký tự null, thay vì ^J.
Có phải vì lý do tương tự, một LF được chuyển đổi thành NUL trong sổ đăng ký tìm kiếm?

Chỉnh sửa 2 :

Trong :h key-notation, chúng ta có thể đọc điều này:

<Nul>       zero            CTRL-@    0 (stored as 10) <Nul>
<NL>        linefeed        CTRL-J   10 (used for <Nul>)

Phần stored as 10trên dòng đầu tiên và used for <Nul>trên dòng thứ hai có thể chỉ ra rằng có một số loại trùng lặp giữa một LF và NUL, và chúng có thể được hiểu là cùng một thứ. Nhưng chúng không thể giống nhau, vì sau khi thực hiện lệnh trước đó :let @/ = @", nếu tôi gõ nở chế độ bình thường để đến lần xuất hiện tiếp theo của 2 dòng foobar, thay vì nhận được kết quả trùng khớp, tôi có thông báo lỗi sau:

E486: Pattern not found: foo^@bar^@

Bên cạnh đó, liên kết này dường như giải thích rằng một NUL biểu thị sự kết thúc của một chuỗi, trong khi đó, một biểu thị cho một kết thúc của một dòng trong một tệp văn bản.

Và nếu một NUL stored as 10đúng như sự trợ giúp nói, đó là mã giống như đối với một LF, làm thế nào Vim có thể tạo ra sự khác biệt giữa 2?

Chỉnh sửa 3 :

Có thể một LF và NUL được mã hóa với cùng một mã thập phân 10, như sự giúp đỡ nói. Và Vim tạo ra sự khác biệt giữa 2 nhờ bối cảnh. Nếu nó gặp một ký tự có mã thập phân nằm 10trong bộ đệm hoặc bất kỳ thanh ghi nào, ngoại trừ các thanh ghi lệnh tìm kiếm và lệnh, nó sẽ hiểu nó là một LF.
Nhưng trong thanh ghi tìm kiếm ( :reg /) nó diễn giải nó là NUL vì trong ngữ cảnh tìm kiếm, Vim chỉ tìm kiếm một chuỗi trong đó khái niệm end of line in a filekhông có ý nghĩa vì một chuỗi không phải là một tệp (điều này thật lạ vì bạn có thể vẫn sử dụng nguyên tử \ntrong một mẫu tìm kiếm, nhưng có lẽ đó chỉ là một tính năng của công cụ regex?). Vì vậy, nó sẽ tự động diễn giải 10như một NUL bởi vì đó là khái niệm gần nhất ( end of stringend of line).

Và theo cách tương tự, trên dòng lệnh / thanh ghi lệnh ( :reg :) nó diễn giải mã 10là CR, vì khái niệm end of line in a filekhông có ý nghĩa ở đây. Khái niệm gần nhất là end of commandVim diễn giải 10như một CR, bởi vì đánh Enterlà cách kết thúc / thực thi lệnh và CR giống như đánh Enter, vì khi bạn chèn một chữ theo nghĩa đen <C-V><Enter>, ^Msẽ được hiển thị.

Có thể cách giải thích của nhân vật có mã 10thay đổi theo ngữ cảnh:

  • cuối dòng trong bộ đệm ( ^J)
  • kết thúc chuỗi trong tìm kiếm ( ^@)
  • kết thúc lệnh trên dòng lệnh ( ^M)

2
Đôi khi sự xuất hiện của các NULL ký tự không mong muốn là do hàm C nằm bên dưới đang xử lý các chuỗi. Đây giải thích về cách C xử lý chuỗi mà bạn liên quan đến giải thích rằng trong nội bộ C delimits dây với một NULL. NULLs hiếm khi xảy ra trong văn bản mà nó làm cho nó trở thành một nhân vật tốt cho mục đích này. Hậu quả của việc này là nếu chương trình C (vim) cố gắng chuyển một chuỗi "trống" vào một hàm C bên trong
the_velour_fog 29/2/2016

2
ví dụ: someFunction(arg1, "")trong đó arg 2 "" là "mục giữa các dấu ngoặc kép, nghĩa đen là không có gì - một" trống ". làm thế nào bạn sẽ kiểm tra điều này - nhưng nó xuất hiện trong tâm trí như một nguyên nhân có thể.
the_velour_fog

1
Xem thêm các cuộc thảo luận về \r\nsự khác biệt trong:substitute .
jamessan

Câu trả lời:


4

Trước tiên, cảm ơn bạn cho bài viết rất toàn diện và chu đáo này.

Sau một số thử nghiệm, tôi đã đi đến kết luận này:

  1. Các ký tự điều khiển được hiển thị bằng cách sử dụng ký hiệu dấu mũ: ^Mfor <CR>(carcar return) và ^Jfor <LF>(line feed). Trong bộ đệm, <EOL>(cuối dòng) được hiển thị dưới dạng các dòng màn hình mới và được nhập bằng phím enter. <EOL>phụ thuộc vào định dạng file của bộ đệm: <EOL> = <CR>|<LF>|<CR><LF>cho mac|unix|dostương ứng.

  2. Khi chỉnh sửa bộ đệm, định dạng tệp luôn được đặt. Để thay đổi định dạng tệp của bộ đệm đã mở, bạn có thể sử dụng lệnh sau đây để chuyển đổi <EOL>:

    :set f[ile]f[ormat]=mac|unix|dos
    

    Ngoài chuyển đổi <EOL>, lệnh này cải <LF>để <CR>khi thay đổi định dạng tập tin từ macđến unix|dos, và ngược lại, <CR>để <LF>khi thay đổi định dạng tập tin từ unix|dosđến mac. Để xem các byte thực của bộ đệm, bạn có thể sử dụng lệnh sau để chuyển đổi biểu diễn văn bản của bộ đệm thành biểu diễn thập lục phân của nó bằng trình soạn thảo thập lục phân thuận tiện xxd:

    :%!xxd
    
  3. Trong các thanh ghi (hiển thị bằng lệnh :reg[isters]hoặc :di[splay]), <EOL>luôn được hiển thị dưới dạng ^J(nhưng không phải tất cả ^Jđều được <EOL>), bất kể định dạng tệp của bộ đệm. Tuy nhiên <EOL>được lưu trữ như họ cần. Để có thể phân biệt trực quan thực ^J(nghĩa là <LF>) với các thanh ghi khác ^J(nghĩa là <EOL>) trong các thanh ghi, bạn có thể sử dụng lệnh sau hiển thị các giá trị thập lục phân thay vì ký hiệu dấu mũ của các ký tự điều khiển khác với <EOL>:

    :set d[ispla]y=uhex
    
  4. Trong các mẫu tìm kiếm và chuỗi thay thế:

    \r = newline different from <EOL> (<CR> if <EOL> = <CR><LF>|<LF>, <LF> if <EOL> = <CR>)
    \n = <EOL>
    
  5. Mọi nơi:

    <C-V><C-M>|<C-V><EOL> = newline different from <EOL>
    <C-V><C-J> = <NUL>
    

    Điều này cho thấy rằng khi định dạng tệp doslà không thể nhập <LF>, vì <EOL> = <CR><LF><C-V><C-M>|<C-V><EOL> = <CR>.

  6. Trong chuỗi thay thế:

    • dòng mới khác với <EOL>được hiểu<EOL>;

    • <EOL>được hiểu<NUL>.

    Vì vậy, theo 4., :%s[ubstitute]/\r/\r/gthay thế mọi dòng mới khác nhau <EOL>trong bộ đệm bằng <EOL>, trong khi :%s[ubstitute]/\n/\n/gthay thế mọi dòng <EOL>trong bộ đệm bằng <NUL>.

  7. Trong thanh ghi tìm kiếm /và thanh ghi lệnh :, <EOL>được chuyển đổi thành

    • dòng mới khác với <EOL>khi được chèn từ một thanh ghi có /<C-R>{register}hoặc :<C-R>{register}tương ứng;

    • <NUL>khi chèn từ một thanh ghi có :let @/=@{register}hoặc :let @:=@{register}tương ứng.

  8. Trong các bộ đệm, dòng mới khác với <EOL>được chuyển đổi thành <EOL>khi được chèn từ một thanh ghi bằng cách sử dụng i<C-R>{register}.

Tại sao Line Feed được chuyển đổi thành một ký tự Null bên trong thanh ghi tìm kiếm và trở thành Vận chuyển trở lại trên dòng lệnh?

Trước khi sao chép <LF>từ thanh ghi không tên "sang các thanh ghi khác, bạn cần nhập <LF>và đặt nó vào thanh ghi ". Nếu định dạng tệp là unix, bạn có thể làm điều đó bằng cách sử dụng yytrên một dòng trống; nếu định dạng tệp là mac, bạn có thể làm điều đó bằng cách sử dụng i<C-V><C-M><Esc>yl; nếu định dạng tệp là dos, bạn không thể nhập <LF>(xem 5.).

Bây giờ tuyên bố của bạn là một phần sai, kể từ khi

  • bạn không sử dụng cùng một phương pháp để sao chép <LF>từ thanh ghi "vào thanh ghi tìm kiếm /và thanh ghi lệnh :. Bạn sử dụng :let @/=@"để sao chép vào sổ đăng ký /:<C-R>"sao chép vào sổ đăng ký :. Sử dụng /<C-R>":<C-R>"tương ứng sẽ cho bạn cùng một kết quả ( <CR>) trong cả hai trường hợp;

  • việc chuyển đổi <LF>diễn ra với hai phương thức sao chép khác nhau của bạn chỉ xảy ra khi định dạng tệp unix. Nếu có mac, <LF>không được chuyển đổi khi được sao chép vào thanh ghi /hoặc thanh ghi :, và nếu đó là dosbạn thậm chí không thể nhập <LF>.

Tuyên bố đúng được đưa ra bởi 7. Nhưng tôi thực sự không biết lý do đằng sau nó.


Tại sao điều này quá khó hiểu ... Tôi đã nghiên cứu qua một số bài đăng về SO và vim-SE và vim giúp đỡ, nhưng không hoàn toàn nhất quán, và vẫn còn nhầm lẫn.
Viol CHƯƠNGin
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.