Quelle est la raison pour laquelle \ r et \ n signifient différentes choses dans la commande s?

13

Nous savons tous que, lors de la recherche, \nest un saut de ligne et \run retour chariot ( ^M), mais lorsque le remplacement \rest un saut de ligne alors que \nest un octet nul ( ^@).

Quelle est l'origine de cette asymétrie? Étant donné que ce comportement est ... pour le moins particulier (et assez contre-productif lorsque vous vous trompez la première fois), je m'attends à ce qu'il y ait une raison historique bizarre.

(accessoirement, existe-t-il un moyen de "corriger" ce comportement et d'obtenir quelque chose de plus intuitif?)

Matteo Italia
la source

Réponses:

10

Au niveau le plus élémentaire, il existe déjà une asymétrie entre les parties de recherche et de remplacement :substitutecar la première est une expression régulière et la seconde est du texte, avec des séquences d'échappement supplémentaires spécifiques . Ceci est juste mis en évidence par l'intuition que vous avez sur ce que \nsignifie.

Par exemple, considérez que \nla recherche ne correspond pas à un littéral \n. Elle correspond à la fin de la séquence d'octets ligne (EOL), qui peut être \r, \r\nou tout simplement en \nfonction de la 'fileformat'de la mémoire tampon.

En ce qui concerne pourquoi \rest utilisé pour signifier "insérer un EOL", il y a un peu d' histoire derrière cela. Vi n'avait aucun moyen de gérer un octet NUL dans un fichier. Vim a amélioré cela en remplaçant les octets NUL par un octet NL en interne (puisque les chaînes C sont délimitées NUL).

Ce détail d'implémentation s'est infiltré dans le comportement de :substitutepuisque \ndans le remplacement est simplement inséré dans la représentation interne de cette ligne, qui est utilisée pour indiquer un octet NUL. \rinsère un EOL, brisant la ligne interne en deux. Vim ne stocke pas réellement les octets EOL en mémoire, au lieu de les (dé) sérialiser lors de la lecture / écriture du tampon.

Il ne peut pas être changé maintenant sans casser les nombreux scripts et la mémoire musculaire de nombreux utilisateurs. Heureusement, c'est documenté dans :help sub-replace-special.

jamessan
la source
6

Un NULoctet est un terminateur de chaîne en C, et pour cette raison, Vim utilise cette convention, décrite dans le manuel à l'adresse suivante :h NL-used-for-Nul:

Les caractères <Nul> dans le fichier sont stockés en tant que <NL> en mémoire. À l'écran, ils sont représentés par "^ @". La traduction se fait lors de la lecture et de l'écriture des fichiers. Pour faire correspondre un <Nul> avec un modèle de recherche, vous pouvez simplement entrer CTRL- @ ou "CTRL-V 000". C'est probablement ce que vous attendez. En interne, le caractère est remplacé par un <NL> dans le motif de recherche. Ce qui est inhabituel, c'est que taper CTRL-V CTRL-J insère également un <NL>, donc recherche également un <Nul> dans le fichier. {Vi ne peut pas du tout gérer les caractères <Nul> dans le fichier}

Cette convention a débordé sur la :s/.../.../commande, mais pas sur la substitute()fonction. \ret \ndans les chaînes de remplacement des substitute()appels, conservez leur signification d'origine.

Je ne pense pas qu'il y ait de raisons plus profondes pour l'un ou l'autre comportement. Vim a simplement évolué de manière organique par rapport à l'original vi. Il n'y a jamais eu de gros plan pour cela, les fonctionnalités ont été empilées les unes sur les autres, avec relativement peu d'efforts pour les garder organisées.

Sato Katsura
la source
0

Les autres clones Vi ne prennent pas en charge \rou \n(comme une véritable barre oblique inverse et une lettre) en substitution, mais le comportement d'un real ^M( CTRL-V Enter) qui signifie diviser la ligne en deux lignes est un comportement standard :

L'entrée d'un <carriage-return> dans repl (qui nécessite un <backslash> d'échappement en mode ex et un <control> -V d'échappement en mode ouvert ou vi ) divisera la ligne à ce point, créant une nouvelle ligne dans le tampon d'édition . Le <carriage-return> doit être jeté.

Dans l'archive Unix History, la première version de BSD ex / vi dans laquelle il apparaît est 4.1cBSD ( @(#)ex_re.c 7.2 10/16/81, et n'est pas présente dans 4BSD ( @(#)ex_re.c 6.2 10/23/80) [4.1a et 4.1b ne sont pas présentes dans l'archive].

Le code pertinent est:

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

Ceci est également mentionné dans le dossier d'actualités :

Il est maintenant possible de séparer les lignes avec des commandes de substitution de vi, en utilisant ^ V <return> dans le rhs. Cela résout la dernière bonne raison d'utiliser le mode de commande ex.

Le comportement précédemment pris en charge dans le mode de commande ex consistait à utiliser une barre oblique inverse (c'est-à-dire une barre oblique inverse suivie d'une véritable nouvelle ligne) pour insérer une nouvelle ligne.

Aléatoire832
la source
0

L'origine de l'asymétrie remonte dans l'histoire de l'informatique.

Version courte:

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

Version longue:
les premiers écrans étaient essentiellement des versions numériques de télétypes (ATS) et utilisaient des codes de contrôle pour générer un comportement similaire aux imprimantes. Le retour chariot a amené le curseur (ou la tête d'impression) dans la colonne de départ. Le saut de ligne est passé à la ligne suivante (sur un écran) et a fait avancer le papier d'une ligne.

Pour les imprimantes, vous deviez faire une paire <CR><LF>ou votre sortie ne serait pas correcte. Sur les premiers écrans, le problème était toujours d'actualité.

DOS (et sorta-Windows après) a suivi l'ancien standard et enregistre le texte avec <CRLF>.

* Le texte NIX (comme la plupart des utilisateurs de vi le connaissent) n'utilise que <LF>pour l'efficacité.

Pour tester sous Windows, utilisez Word / Wordpad et enregistrez quelques lignes de texte "comme type: Texte - format MS-DOS". Ouvrez ensuite ce même fichier dans le Bloc-notes. Cela devrait avoir l'air normal. Enregistrez ensuite le même fichier dans Word / Wordpad "en tant que type: Texte". Le Bloc-notes ignorera toutes les nouvelles lignes et exécutera les lignes ensemble. [Le format de texte du Bloc-notes correspond par défaut à la \r\ncombinaison tandis que Word / Wordpad par défaut \n.]

\ r est l'équivalent de code de <CR>

\ n est l'équivalent de code de <LF>

Et dans mon expérience (très limitée) avec vi, il essaierait de "corriger" la <CRLF>combinaison de mon éditeur de texte DOS. vi a fini par supprimer un caractère, en le remplaçant par <NUL>. Une grande partie de la raison pour laquelle j'ai cessé d'utiliser vi.

Robin
la source
2
Alors que toutes vos informations est intéressant, il dit seulement pourquoi \rest <CR>et \nest <LF>. Il n'aborde pas la question réelle de savoir pourquoi \n\rse comporter différemment dans différents contextes.
Tumbler41
Je vous remercie! :-) Je le changeais quand tu as répondu. (Ajout du dernier paragraphe.)
Robin