Qual è la logica di \ r e \ n che significa cose diverse nel comando s?


13

Sappiamo tutti che, durante la ricerca, \nè newline ed \rè il ritorno a capo ( ^M), ma quando la sostituzione \rè newline mentre \nè un byte null ( ^@).

Qual è l'origine di questa asimmetria? Dato che questo comportamento è ... a dir poco strano (e alquanto controproducente quando la sbagli la prima volta) mi aspetto che ci sia una strana ragione storica.

(per inciso, c'è un modo per "correggere" questo comportamento e ottenere qualcosa di più intuitivo?)

Risposte:


10

Al livello più elementare, esiste già un'asimmetria tra la ricerca e la sostituzione di parti :substituteperché la prima è un'espressione regolare e la seconda è un testo, con specifiche sequenze di escape aggiuntive . Questo è appena evidenziato dall'intuizione che hai su ciò che \nsignifica.

Ad esempio, considera che \nnella ricerca non corrisponde un letterale \n. Esso corrisponde alla fine della sequenza di byte linea (EOL), che può essere \r, \r\no semplicemente \na seconda del 'fileformat'del buffer.

Per quanto riguarda il motivo per cui \rsi intende "inserire un EOL", c'è dietro un po 'di storia . Vi non aveva modo di gestire un byte NUL in un file. Vim è migliorato su questo sostituendo internamente i byte NUL con un byte NL (poiché le stringhe C sono delimitate da NUL).

Questo dettaglio di implementazione trapelato nel comportamento di :substitutepoiché \nnella sostituzione viene semplicemente inserito nella rappresentazione interna di quella linea, che viene utilizzata per indicare un byte NUL. \rinserisce un EOL, spezzando la linea interna in due. Vim in realtà non memorizza i byte EOL in memoria, invece (de) serializzandoli durante la lettura / scrittura del buffer.

Non può essere cambiato ora senza rompere i molti script e la memoria muscolare di molti utenti. Per fortuna, è documentato in :help sub-replace-special.


6

Un NULbyte è un terminatore di stringa in C, e per questo motivo Vim utilizza questa convenzione, descritta nel manuale all'indirizzo :h NL-used-for-Nul:

I caratteri <Nul> nel file sono memorizzati come <NL> in memoria. Sul display vengono visualizzati come "^ @". La traduzione viene eseguita durante la lettura e la scrittura di file. Per abbinare un <Nul> a un modello di ricerca, basta inserire CTRL- @ o "CTRL-V 000". Questo è probabilmente proprio quello che ti aspetti. Internamente il carattere viene sostituito con un <NL> nel modello di ricerca. Ciò che è insolito è che digitando CTRL-V CTRL-J si inserisce anche un <NL>, quindi si cerca anche un <Nul> nel file. {Vi non riesce a gestire <Nul> caratteri nel file}

Questa convenzione si è estesa al :s/.../.../comando, ma non alla substitute()funzione. \re \nnelle stringhe di sostituzione le substitute()chiamate mantengono il loro significato originale.

Non penso che ci siano ragioni più profonde per entrambi i comportamenti. Vim si è semplicemente evoluto in modo organico dall'originale vi. Non c'è mai stato un grande progetto per questo, le funzionalità sono state semplicemente accatastate l'una sull'altra, con relativamente poco sforzo per mantenerle organizzate.


0

Altri cloni Vi non supportano \ro \n(come una barra rovesciata e una lettera reale) in sostituzione, ma il comportamento di un reale ^M( CTRL-V Enter) che significa dividere la linea in due linee è il comportamento standard :

Immettendo <carriage-return> in repl (che richiede una <backslash> in modalità ex e una <control> -V in modalità open o vi in escape ) dividerà la linea in quel punto, creando una nuova riga nel buffer di modifica . Il <carriage-return> deve essere scartato.

Nell'archivio di Unix History, la prima versione di BSD ex / vi in ​​cui appare è 4.1cBSD ( @(#)ex_re.c 7.2 10/16/81, e non è presente in 4BSD ( @(#)ex_re.c 6.2 10/23/80) [4.1a e 4.1b non sono presenti nell'archivio].

Il codice rilevante è:

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

Questo è anche menzionato nel file delle notizie :

Ora è possibile dividere le linee con i comandi sostitutivi di vi, usando ^ V <return> in rhs. Questo si occupa dell'ultima buona ragione per usare la modalità comando ex.

Il comportamento precedentemente supportato in modalità comando ex era di backslash-enter (ovvero backslash seguito da una nuova riga reale) per inserire una nuova riga.


0

L'origine dell'asimmetria risale alla storia dell'informatica.

Versione breve:

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

Versione lunga:
le prime schermate erano essenzialmente versioni digitali dei teletipi (TTY) e utilizzavano i codici di controllo per generare un comportamento simile alle stampanti. Carriage-return ha portato il cursore (o la testina di stampa) sulla colonna iniziale. L'avanzamento della riga è avanzato alla riga successiva (su uno schermo) e ha fatto avanzare la carta di una riga.

Per le stampanti, è stato necessario eseguire un accoppiamento <CR><LF>o l'output non sarebbe stato corretto. Sulle prime schermate, il problema era ancora vero.

DOS (e una specie di Windows dopo) ha seguito il vecchio standard e salva il testo con <CRLF>.

* Il testo NIX (come è noto alla maggior parte degli utenti vi) viene utilizzato solo a <LF>fini di efficienza.

Per eseguire il test in Windows, utilizzare Word / Wordpad e salvare alcune righe di testo "come tipo: testo - formato MS-DOS". Quindi apri lo stesso file in Blocco note. Dovrebbe apparire normale. Quindi salvare lo stesso file in Word / Wordpad "come tipo: Testo". Blocco note ignorerà tutte le nuove righe ed eseguirà le linee insieme. [Il formato di testo del Blocco note è impostato automaticamente sulla \r\ncombinazione mentre Word / Wordpad sono impostati di default \n.]

è l'equivalente del codice di <CR>

\ n è l'equivalente in codice di <LF>

E nella mia (molto limitata) esperienza con vi, proverebbe a "correggere" la <CRLF>combinazione dal mio editor di testo DOS. vi ha finito per rimuovere un carattere, sostituendolo con <NUL>. Gran parte del motivo per cui ho smesso di usare vi.


2
Mentre tutte le tue informazioni sono interessanti, dice solo perché lo \rè <CR>e lo \nè <LF>. Non affronta la vera domanda del perché \n\rcomportarsi diversamente in contesti diversi.
Tumbler41,

Grazie! :-) Lo stavo cambiando quando hai risposto. (Aggiunto l'ultimo paragrafo.)
Robin,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.