Почему перевод строки переводится в нулевой символ внутри регистра поиска и в возврат каретки в командной строке?

12

Если у меня есть следующий текст:

foo
bar

Я визуально выбираю и копирую.
Текст теперь хранится в безымянном регистре, "и вот его содержимое (вывод :reg "):

""   foo^Jbar^J

В соответствии с этим графиком , кажется, что ^Jэто обозначение каретки для перевода строки.

Если я хочу дублировать безымянный регистр в aрегистре, набрав: :let @a = @"
Вот его содержимое (вывод :reg a):

"a   foo^Jbar^J

Это не изменилось.

Если я теперь продублирую его в регистре поиска, набрав :let @/ = @", вот его содержимое (вывод :reg /):

"/   foo^@bar^@

Согласно предыдущему графику, это похоже ^@на символ каретки для нулевого символа.
Почему перевод строки автоматически преобразуется в нулевой символ в регистре поиска (но не в aрегистре)?

Если я вставляю безымянный регистр в командной строке (или в поиске после /), набрав :<C-R>", вот что вставлено:

:foo^Mbar^M

Опять же, в соответствии с последним графиком, ^Mпохоже, каретная нотация для возврата каретки.
Почему перевод строки автоматически преобразуется в возврат каретки в командной строке?

Редактировать :

Обычно вы можете вставить буквенный управляющий символ, набрав:
<C-V><C-{character in caret notation}>

Например, вы можете вставить в буквальном смысле <C-R>, набрав <C-V><C-R>.
Вы можете сделать это для, казалось бы, любого управляющего персонажа.
Однако я заметил, что я не могу вставить буквальный LF внутри буфера или в командной строке, потому что, если я наберу: <C-V><C-J>он вставляет ^@нулевой символ вместо ^J.
По той же причине LF преобразуется в NUL внутри регистра поиска?

Изменить 2 :

В :h key-notation, мы можем прочитать это:

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

stored as 10Часть на первой линии и used for <Nul>на второй линии может свидетельствовать о том , что есть какая - то перекрытия между LF и NUL, и что они могут быть интерпретированы как то же самое. Но они не могут быть одинаковыми, потому что после выполнения предыдущей команды :let @/ = @", если я набираю текст nв обычном режиме, чтобы перейти к следующему вхождению из 2 строк, fooи barвместо получения положительного совпадения у меня появляется следующее сообщение об ошибке:

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

Кроме того, эта ссылка, кажется, объясняет, что NUL обозначает конец строки, тогда как LF обозначает конец строки в текстовом файле.

И если NUL, stored as 10как говорится в справке, это тот же код, что и для LF, как Vim может сделать разницу между двумя?

Изменить 3 :

Возможно, LF и NUL кодируются с одним и тем же десятичным кодом 10, как говорится в справке. И Vim делает разницу между двумя благодаря контексту. Если он встречает символ, десятичный код которого находится 10в буфере или любом регистре, кроме регистров поиска и команд, он интерпретирует его как LF.
Но в search register ( :reg /) он интерпретирует его как NUL, потому что в контексте поиска Vim ищет только строку, в которой концепция end of line in a fileне имеет смысла, потому что строка не является файлом (что странно, поскольку вы можете по-прежнему использовать атом \nв искомом шаблоне, но, возможно, это только особенность движка регулярных выражений?). Таким образом, он автоматически интерпретируется 10как NUL, потому что это ближайшая концепция ( end of stringend of line).

И точно так же в командной строке / command register ( :reg :) он интерпретирует код 10как CR, потому что концепция end of line in a fileздесь не имеет смысла. Ближайшая концепция end of commandтак Vim толкует 10как CR, так как ударять Enterпуть до конца / выполнить команду и CR такой же , как удары Enter, так как при вставке буквального с <C-V><Enter>, ^Mотображаются.

Может быть, интерпретация символа, чей код 10меняется в зависимости от контекста:

  • конец строки в буфере ( ^J)
  • конец строки в поиске ( ^@)
  • конец команды в командной строке ( ^M)
Сагино
источник
2
Иногда появление неожиданных NULL символов вызвано базовой функцией C, которая обрабатывает строки. Это объяснение того, как C обрабатывает строки, с которыми вы связались, объясняет, что внутренне C разделяет строки с помощью NULL. NULLв тексте встречаются достаточно редко, что делает его хорошим персонажем для этой цели. Следствием этого является то, что если программа C (vim) пыталась передать «пустую» строку во внутреннюю функцию C
the_velour_fog
2
например, someFunction(arg1, "")где arg 2 было, "" т. е. «элемент между кавычками, который буквально ничто -« пустой ». Может быть NULL, потому что он был« добавлен »базовой реализацией C, поскольку он ограничил строку. Я не знаю как бы вы проверили это - но это приходит на ум в качестве возможной причины
the_velour_fog
1
Смотрите также обсуждение \rи \nразницу в:substitute .
Jamessan

Ответы:

4

Во-первых, спасибо за этот очень полный и вдумчивый пост.

После некоторых испытаний я пришел к такому выводу:

  1. Управляющие символы отображаются с использованием обозначения каретки: ^Mдля <CR>(возврат каретки) и ^Jдля <LF>(перевод строки). В буферах <EOL>(конец строки) отображаются как новые строки экрана и вводятся клавишей ввода. <EOL>зависит от формата файла буфера: <EOL> = <CR>|<LF>|<CR><LF>для mac|unix|dosсоответственно.

  2. При редактировании буфера формат файла всегда устанавливается. Чтобы изменить формат файла открытого буфера, вы можете использовать следующую команду, которая преобразует <EOL>:

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

    Кроме преобразования <EOL>, эта команда преобразует <LF>в <CR>при изменении формата файла от macдо unix|dos, и наоборот, <CR>чтобы <LF>при изменении формата файла от unix|dosк mac. Чтобы увидеть реальные байты буфера, вы можете использовать следующую команду, которая преобразует текстовое представление буфера в его шестнадцатеричное представление, используя удобный шестнадцатеричный редактор xxd:

    :%!xxd
    
  3. В регистрах (показавших с командой :reg[isters]или :di[splay]) <EOL>всегда отображаются в виде ^J(но не все ^Jэто <EOL>), независимо от формата файла буфера. Однако <EOL>будут сохранены , как они должны. Чтобы иметь возможность отличать визуально реальные ^J(то есть <LF>) от других ^J(то есть <EOL>) в регистрах, вы можете использовать следующую команду, которая отображает шестнадцатеричные значения вместо обозначения каретки контрольных символов, отличного от <EOL>:

    :set d[ispla]y=uhex
    
  4. В шаблонах поиска и строках подстановки:

    \r = newline different from <EOL> (<CR> if <EOL> = <CR><LF>|<LF>, <LF> if <EOL> = <CR>)
    \n = <EOL>
    
  5. Где угодно:

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

    Это показывает, что при формате файла dosввод невозможен <LF>, так как <EOL> = <CR><LF>и <C-V><C-M>|<C-V><EOL> = <CR>.

  6. В строках подстановки:

    • новая строка отличается от <EOL>будут интерпретироваться , как <EOL>;

    • <EOL>которые интерпретируются , как <NUL>.

    Таким образом, согласно 4., :%s[ubstitute]/\r/\r/gзаменяет каждую новую строку, отличную от <EOL>в буфере <EOL>, в то время как :%s[ubstitute]/\n/\n/gзаменяет каждую <EOL>в буфере с <NUL>.

  7. В поле поиска регистр /и регистр команд :, <EOL>которые преобразуются в

    • новая строка отличается от <EOL>вставленной из регистра с /<C-R>{register}или :<C-R>{register}соответственно;

    • <NUL>при вставке из регистра с :let @/=@{register}или :let @:=@{register}соответственно.

  8. В буферах, отличается от перевода строки <EOL>будут преобразованы , чтобы <EOL>при вставке из регистра , используя i<C-R>{register}.

Почему перевод строки переводится в нулевой символ внутри регистра поиска и в возврат каретки в командной строке?

Перед копированием <LF>из безымянного регистра "в другие регистры, вам необходимо ввести <LF>и внести его в регистр ". Если формат файла unix, вы можете сделать это, используя yyпустую строку; если формат файла mac, вы можете сделать это с помощью i<C-V><C-M><Esc>yl; если формат файла dos, вы не можете ввести <LF>(см. 5.).

Теперь ваше утверждение частично неверно, так как

  • Вы не используете один и тот же метод для копирования <LF>из регистра "в регистр поиска и регистр /команд :. Вы используете :let @/=@"для копирования в реестр /и :<C-R>"для копирования в реестр :. Использование /<C-R>"и :<C-R>"соответственно даст вам одинаковый результат ( <CR>) в обоих случаях;

  • преобразования, <LF>которые происходят с вашими двумя различными методами копирования, происходят только тогда, когда формат файла unix. Если mac, <LF>это не конвертируются при копировании в реестре /или реестре :, и если dosвы не можете даже вход <LF>.

Правильное утверждение дает 7. Но я действительно не знаю причин этого.

Maggyero
источник
Почему это так трудно понять ... Я изучил несколько постов по SO и vim-SE и помощи vim, но не полностью согласованным и все еще запутанным.
Виолаптерин