Jakie jest uzasadnienie dla \ r, a \ n oznacza różne rzeczy w poleceniu?

13

Wszyscy wiemy, że podczas wyszukiwania \njest znakiem nowej linii i jest znakiem \rpowrotu karetki ( ^M), ale podczas zastępowania \rjest znakiem nowej linii, podczas gdy \njest bajtem pustym ( ^@).

Jakie jest pochodzenie tej asymetrii? Biorąc pod uwagę, że takie zachowanie jest ... co najmniej dziwne (i przynosi efekt przeciwny do zamierzonego, gdy popełnisz błąd za pierwszym razem), spodziewam się, że istnieje jakiś dziwny historyczny powód.

(nawiasem mówiąc, czy jest jakiś sposób, aby „naprawić” to zachowanie i uzyskać coś bardziej intuicyjnego?)

Matteo Italia
źródło

Odpowiedzi:

10

Na najbardziej podstawowym poziomie istnieje już asymetria między częściami wyszukiwania i zamiany, :substituteponieważ pierwsza z nich jest wyrażeniem regularnym, a druga tekstem, z określonymi dodatkowymi sekwencjami ucieczki . Podkreśla to intuicja, którą dysponujesz \n.

Weźmy na przykład pod uwagę, że \nwyszukiwanie nie pasuje do literału \n. Pasuje na końcu linii (EOL) sekwencja bajtów, które mogą być \r, \r\nalbo po prostu \n, stosownie do 'fileformat'bufora.

Jeśli chodzi o \rto, co oznacza „wstaw EOL”, kryje się za tym pewna historia . Vi nie miała możliwości obsługi bajtu NUL w pliku. Vim poprawił to, zastępując wewnętrznie bajty NUL bajtem NL (ponieważ łańcuchy C są rozdzielane NUL).

Ten szczegół implementacji wyciekł z zachowania, :substituteponieważ \nw zastępstwie jest po prostu wstawiany do wewnętrznej reprezentacji tej linii, która jest używana do wskazania bajtu NUL. \rwstawia EOL, przerywając wewnętrzną linię na pół. Vim tak naprawdę nie przechowuje bajtów EOL w pamięci, zamiast (od) serializacji ich podczas odczytu / zapisu bufora.

Nie można go teraz zmienić bez zerwania wielu skryptów i pamięci mięśniowej wielu użytkowników. Na szczęście jest to udokumentowane :help sub-replace-special.

jamessan
źródło
6

NULBajt jest terminator ciąg w C, i z tego powodu Vim używa tej konwencji, opisanej w instrukcji na :h NL-used-for-Nul:

<Nul> znaki w pliku są przechowywane w pamięci jako <NL>. Na wyświetlaczu są pokazane jako „^ @”. Tłumaczenie odbywa się podczas odczytu i zapisu plików. Aby dopasować <Nul> do wzorca wyszukiwania, wystarczy wpisać CTRL- @ lub „CTRL-V 000”. Prawdopodobnie właśnie tego oczekujesz. Wewnętrznie znak jest zastępowany znakiem <NL> we wzorcu wyszukiwania. Niezwykłe jest to, że wpisanie CTRL-V CTRL-J powoduje także wstawienie <NL>, a zatem wyszukuje również <Nul> w pliku. {Vi nie może w ogóle obsługiwać <Nul> znaków w pliku}

Ta konwencja przeniosła się na :s/.../.../polecenie, ale nie na substitute()funkcję. \ra \nw ciągach zastępczych w substitute()połączeniach zachowaj swoje oryginalne znaczenie.

Nie sądzę, aby istniały głębsze powody takiego zachowania. Vim po prostu ewoluował organicznie z oryginału vi. Nigdy nie było żadnego dużego planu, funkcje były po prostu nakładane jeden na drugi, przy stosunkowo niewielkim wysiłku, aby je uporządkować.

Sato Katsura
źródło
0

Inne klony Vi nie obsługują \rlub \n(jako prawdziwy odwrotny ukośnik i litera) w zamianie, ale zachowanie rzeczywistego ^M( CTRL-V Enter) oznaczającego podzielenie linii na dwie linie jest standardowym zachowaniem :

Wpisanie <powrót karetki> w repl (co wymaga ucieczki <lashback> w trybie ex i ucieczki <Control> -V w trybie otwartym lub vi ) rozdzieli linię w tym punkcie, tworząc nową linię w buforze edycji . <Powrót karetki> należy odrzucić.

W archiwum historii Unixa pierwsza wersja BSD ex / vi, w której się pojawia, to 4.1cBSD ( @(#)ex_re.c 7.2 10/16/81i nie jest obecna w 4BSD ( @(#)ex_re.c 6.2 10/23/80) [4.1a i 4.1b nie są obecne w archiwum].

Odpowiedni kod to:

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

Jest to również wspomniane w pliku aktualności :

Można teraz podzielić linie za pomocą komend zastępczych z vi, używając ^ V <powrót> w prawej stronie. Daje to ostatnią dobrą przyczynę korzystania z trybu poleceń ex.

Poprzednio obsługiwane zachowanie w trybie komend ex było dla odwrotnego ukośnika-enter (tj. Odwrotnego ukośnika, po którym następuje prawdziwa nowa linia) w celu wstawienia nowej linii.

Losowo 832
źródło
0

Geneza asymetrii sięga wstecz do historii obliczeń.

Krótka wersja:

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

Wersja długa:
pierwsze ekrany były w zasadzie cyfrowymi wersjami teletypów (TTY) i wykorzystywały kody sterujące do generowania podobnych zachowań do drukarek. Powrót karetki zabrał kursor (lub głowicę drukującą) do kolumny początkowej. Podawanie linii przechodzi do następnego rzędu (na ekranie) i podaje papier do przodu o jedną linię.

W przypadku drukarek trzeba było sparować, w <CR><LF>przeciwnym razie wydruk nie będzie wyglądał dobrze. Na wczesnych ekranach problem nadal się sprawdzał.

DOS (i później Windows) postępował zgodnie ze starym standardem i zapisuje tekst za pomocą <CRLF>.

* Tekst NIX (jak większość użytkowników vi zna) używa wyłącznie w <LF>celu zwiększenia wydajności.

Aby przetestować w systemie Windows, użyj programu Word / Wordpad i zapisz kilka wierszy tekstu „jako typ: Tekst - format MS-DOS”. Następnie otwórz ten sam plik w Notatniku. Powinno to wyglądać normalnie. Następnie zapisz ten sam plik w programie Word / Wordpad „jako typ: Tekst”. Notatnik zignoruje wszystkie znaki nowej linii i poprowadzi linie razem. [ \r\nDomyślny format tekstu w Notatniku to kombinacja, podczas gdy Word / Wordpad domyślnie to \n.]

\ r jest kodowym odpowiednikiem <CR>

\ n jest kodowym odpowiednikiem <LF>

W moim (bardzo ograniczonym) doświadczeniu z vi, próbowałbym „naprawić” <CRLF>kombinację z mojego edytora tekstowego DOS. vi skończyło się usunięciem jednej postaci, zastępując ją <NUL>. Duża część powodów, dla których przestałem używać vi.

Rudzik
źródło
2
Chociaż wszystkie twoje informacje są interesujące, to tylko mówi, dlaczego \rjest <CR>i \njest <LF>. Nie odnosi się do faktycznego pytania, dlaczego \n\rzachowują się inaczej w różnych kontekstach.
Tumbler41,
Dziękuję Ci! :-) Zmieniałem to, kiedy odpowiedziałeś. (Dodano ostatni akapit.)
Robin