Що обґрунтовує, що \ r і \ n означають різні речі в команді s?


13

Усі ми знаємо, що при пошуку - \nце новий рядок і \rце повернення каретки ( ^M), але при заміні \rнової лінії \nє нульовим байтом ( ^@).

Яке походження цієї асиметрії? Зважаючи на те, що така поведінка є найменш властивою (і досить контрпродуктивною, коли ви помиляєтесь вперше), я думаю, що є якась химерна історична причина.

(до речі, чи є якийсь спосіб "виправити" таку поведінку і отримати щось більш інтуїтивне?)

Відповіді:


10

На самому базовому рівні вже існує асиметрія між частинами пошуку та заміни, :substituteтому що перший є регулярним виразом, а другий - текстом із певними додатковими послідовностями . Це лише підкреслюється вашою інтуїцією щодо того, що \nозначає.

Наприклад, врахуйте, що \nпошук не відповідає буквальному \n. Це відповідає кінцю рядка (EOL) послідовності байтів, які можуть бути \r, \r\nабо просто в \nзалежності від 'fileformat'буфера.

Що стосується того, чому \rвикористовується слово "вставити EOL", за цим є деяка історія . У файлу не було можливості обробити байт NUL. Vim покращив це, замінивши внутрішньо байт NUL на байт NL (оскільки рядки C обмежені NUL).

Ця деталізація реалізації просочилася у поведінці, :substituteоскільки \nпри заміні просто вставляється у внутрішнє представлення цього рядка, який використовується для позначення байта NUL. \rвставляє EOL, розбиваючи внутрішню лінію надвоє. Vim насправді не зберігає байти EOL у пам'яті, замість цього (де) їх серіалізує під час читання / запису буфера.

Зараз його неможливо змінити, не порушивши безліч сценаріїв і м'язової пам'яті багатьох користувачів. На щастя, це задокументовано в :help sub-replace-special.


6

NULБайт являє собою рядок в C - термінатор, і з цієї причини Вім використовує цю конвенцію, описаної в керівництві по :h NL-used-for-Nul:

Символи <Nul> у файлі зберігаються як <NL> в пам'яті. На дисплеї вони показані як "^ @". Переклад здійснюється під час читання та запису файлів. Щоб відповідати <Nul> з шаблоном пошуку, ви можете просто ввести CTRL- @ або "CTRL-V 000". Це, мабуть, саме те, чого ви очікуєте. Внутрішній символ замінюється на <NL> в шаблоні пошуку. Що незвично, це те, що введення CTRL-V CTRL-J також вставляє <NL>, таким чином, також шукає <Nul> у файлі. {Vi взагалі не може обробити <Nul> символів у файлі}

Ця конвенція перекинулася на :s/.../.../команду, але не на substitute()функцію. \rа \nв рядках заміни у substitute()викликах зберігають своє первісне значення.

Я не думаю, що для будь-якої поведінки є більш глибокі причини. Вім просто органічно розвинувся з оригіналу vi. Ніколи не було великого плану для цього, функції просто збиралися один на одного, з відносно невеликими зусиллями, щоб організувати їх.


0

Інші клони Vi не підтримують \rабо \n(як справжній зворотний косий лист і літеру) в підстановці, але поведінка реального ^M( CTRL-V Enter) сенсу розділити лінію на дві лінії є стандартною поведінкою :

Введення <carriage-return> у repl (для чого потрібен пробіг <backslash> у колишньому режимі та увімкнення <control> -V у відкритому або vi режимі) розбиває рядок у цій точці, створюючи новий рядок у буфері редагування . <Перевезення каретки> слід відмовитися.

В архіві історії Unix перша версія BSD ex / vi, в якій він з'являється, - 4.1cBSD ( @(#)ex_re.c 7.2 10/16/81і в 4BSD ( @(#)ex_re.c 6.2 10/23/80) відсутня [в архіві немає 4.1a та 4.1b).

Відповідний код:

/* ^V <return> from vi to split lines */
if (c == '\r')
    c = '\n';

Про це також йдеться у файлі новин :

Тепер можна розділити рядки командами-замінниками від vi, використовуючи ^ V <return> в rhs. Це враховує останню вагому причину для використання режиму командування ex.

Раніше підтримувана поведінка в режимі колишнього командування полягала в тому, щоб вводити новий рядок (тобто зворотну косу рису з наступним реальним новим рядком).


0

Походження асиметрії бере свій шлях до історії обчислень.

Коротка версія:

<CR> & <LF>  (Carriage-Return and Linefeed) 
== 
\r & \n

Довга версія:
Перші екрани в основному були цифровими версіями телетипів (TTY) і використовували керуючі коди для створення аналогічної поведінки принтерів. Каретка-повернення взяла курсор (або друкувальну головку) до стартової колонки. Подача ліній переходила до наступного ряду (на екрані) і подала папір вперед на один рядок.

Для принтерів вам довелося робити в парі, інакше <CR><LF>ваш вихід не буде виглядати правильно. На ранніх екранах проблема все ще залишається актуальною.

DOS (і сортування Windows після) дотримувались старого стандарту та зберігає текст <CRLF>.

* Текст NIX (як знайомий більшості користувачів vi) використовується лише <LF>для ефективності.

Для тестування в Windows використовуйте Word / Wordpad і збережіть кілька рядків тексту "як тип: Текст - формат MS-DOS". Потім відкрийте той самий файл у Блокноті. Це повинно виглядати нормально. Потім збережіть той самий файл у Word / Wordpad "як тип: Текст". Блокнот ігнорує всі нові рядки та запускатиме рядки разом. [Текстовий формат блокнота за замовчуванням відповідає \r\nкомбінації, тоді як Word / Wordpad за замовчуванням \n.]

\ r - еквівалент коду <CR>

\ n - еквівалент коду <LF>

І в моєму (дуже обмеженому) досвіді роботи з vi, він би намагався "виправити" <CRLF>комбінацію з мого редактора тексту DOS. vi видав один символ, замінивши його <NUL>. Значна частина причини, по якій я припинив використовувати vi.


2
Незважаючи на те, що вся ваша інформація цікава, вона лише говорить про те, чому \rце так <CR>і \nє <LF>. Це не стосується актуального питання, чому \n\rповодитися по- різному в різних контекстах.
Tumbler41

Дякую! :-) Я змінив це, коли ти відповів. (Додано останній абзац.)
Робін
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.