¿Cuál es la razón para \ r y \ n que significan cosas diferentes en el comando s?

13

Todos sabemos que, cuando se busca, \nes nueva línea y \res retorno de carro ( ^M), pero cuando se reemplaza \res nueva línea mientras que \nes un byte nulo ( ^@).

¿Cuál es el origen de esta asimetría? Dado que este comportamiento es ... peculiar por decir lo menos (y bastante contraproducente cuando te equivocas la primera vez) espero que haya alguna razón histórica extraña.

(por cierto, ¿hay alguna forma de "arreglar" este comportamiento y obtener algo más intuitivo?)

Matteo Italia
fuente

Respuestas:

10

En el nivel más básico, ya existe una asimetría entre las partes de búsqueda y reemplazo :substituteporque la primera es una expresión regular y la segunda es texto, con secuencias de escape adicionales específicas . Esto solo se destaca por la intuición que tienes sobre lo que \nsignifica.

Por ejemplo, considere que \nen la búsqueda no coincide con un literal \n. Se coincide con el final de la secuencia de bytes de línea (EOL), que puede ser \r, \r\n, o simplemente \nen función de la 'fileformat'de la memoria intermedia.

En cuanto a por qué \rse usa para significar "insertar una EOL", hay algo de historia detrás de eso. Vi no tenía forma de manejar un byte NUL en un archivo. Vim mejoró eso al reemplazar los bytes NUL con un byte NL internamente (ya que las cadenas C están delimitadas por NUL).

Este detalle de implementación se filtró en el comportamiento de :substituteya que \nen el reemplazo simplemente se inserta en la representación interna de esa línea, que se utiliza para indicar un byte NUL. \rinserta una EOL, rompiendo la línea interna en dos. Vim en realidad no almacena los bytes EOL en la memoria, sino que (los) serializa cuando lee / escribe el búfer.

No se puede cambiar ahora sin romper los muchos scripts y la memoria muscular de muchos usuarios. Afortunadamente, está documentado en :help sub-replace-special.

jamessan
fuente
6

Un NULbyte es un terminador de cadena en C, y por esta razón Vim usa esta convención, descrita en el manual en :h NL-used-for-Nul:

Los caracteres <Nul> en el archivo se almacenan como <NL> en la memoria. En la pantalla se muestran como "^ @". La traducción se realiza al leer y escribir archivos. Para hacer coincidir un <Nul> con un patrón de búsqueda, simplemente ingrese CTRL- @ o "CTRL-V 000". Esto es probablemente lo que esperas. Internamente, el carácter se reemplaza con un <NL> en el patrón de búsqueda. Lo inusual es que escribir CTRL-V CTRL-J también inserta un <NL>, por lo tanto, también busca un <Nul> en el archivo. {Vi no puede manejar <Nul> caracteres en el archivo en absoluto}

Esta convención se ha extendido al :s/.../.../comando, pero no a la substitute()función. \ry \nen cadenas de reemplazo en substitute()llamadas mantienen su significado original.

No creo que haya razones más profundas para ninguno de los comportamientos. Vim simplemente ha evolucionado orgánicamente desde el original vi. Nunca hubo un gran plan para ello, las características se apilaron una encima de la otra, con relativamente poco esfuerzo para mantenerlas organizadas.

Sato Katsura
fuente
0

Otros clones Vi no admiten \ro \n(como una barra invertida y una letra reales) en sustitución, pero el comportamiento de un real ^M( CTRL-V Enter) que significa dividir la línea en dos líneas es el comportamiento estándar :

Al ingresar un <carriage-return> en repl (que requiere un <backslash> de escape en modo ex y un <control> -V de escape en modo abierto o vi ) dividirá la línea en ese punto, creando una nueva línea en el búfer de edición . El <carriage-return> se descartará.

En el archivo de Historia de Unix, la primera versión de BSD ex / vi en la que aparece es 4.1cBSD ( @(#)ex_re.c 7.2 10/16/81y no está presente en 4BSD ( @(#)ex_re.c 6.2 10/23/80) [4.1a y 4.1b no están presentes en el archivo]).

El código relevante es:

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

Esto también se menciona en el archivo de noticias :

Ahora es posible dividir líneas con comandos sustitutos de vi, usando ^ V <return> en rhs. Esto se ocupa de la última buena razón para usar el modo de comando ex.

El comportamiento admitido anteriormente en el modo de comando ex era para la barra invertida-enter (es decir, la barra invertida seguida de una nueva línea real) para insertar una nueva línea.

Aleatorio832
fuente
0

El origen de la asimetría se remonta a la historia de la computación.

Version corta:

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

Versión larga: las
primeras pantallas eran básicamente versiones digitales de teletipos (TTY) y usaban códigos de control para generar un comportamiento similar al de las impresoras. El retorno de carro llevó el cursor (o el cabezal de impresión) a la columna de inicio. El avance de línea avanzó a la siguiente fila (en una pantalla) y alimentó el papel una línea hacia adelante.

Para las impresoras, tenía que hacer un emparejamiento <CR><LF>o su salida no se vería bien. En las primeras pantallas, el problema seguía siendo cierto.

DOS (y sorta-Windows después) siguieron el estándar anterior y guardan texto con <CRLF>.

* El texto NIX (como la mayoría de los usuarios de vi están familiarizados) solo se usa <LF>para la eficiencia.

Para probar en Windows, use Word / Wordpad y guarde algunas líneas de texto "como tipo: Texto - formato MS-DOS". Luego abra el mismo archivo en el Bloc de notas. Debería verse normal. Luego guarde el mismo archivo en Word / Wordpad "como tipo: Texto". El Bloc de notas ignorará todas las líneas nuevas y las ejecutará juntas. [El formato de texto del Bloc de notas está predeterminado en la \r\ncombinación, mientras que Word / Wordpad está predeterminado en \n.]

\ r es el código equivalente de <CR>

\ n es el código equivalente de <LF>

Y en mi (muy limitada) experiencia con vi, intentaría "arreglar" la <CRLF>combinación de mi editor de texto DOS. vi terminó eliminando un personaje, reemplazándolo con <NUL>. Una gran parte de la razón por la que dejé de usar vi.

Robin
fuente
2
Si bien toda su información es interesante, solo dice por qué \res <CR>y \nes <LF>. No aborda la pregunta real de por qué \n\rcomportarse de manera diferente en diferentes contextos.
Tumbler41
¡Gracias! :-) Lo estaba cambiando cuando respondiste. (Se agregó el último párrafo.)
Robin