Warum wird ein Zeilenvorschub in der Befehlszeile in ein Nullzeichen im Suchregister und in einen Wagenrücklauf umgewandelt?


12

Wenn ich folgenden Text habe:

foo
bar

Ich wähle es visuell aus und kopiere es.
Der Text ist jetzt im unbenannten Register gespeichert "und hier ist sein Inhalt (Ausgabe von :reg "):

""   foo^Jbar^J

Nach dieser Tabelle handelt es sich anscheinend ^Jum die Caret-Notation für einen Zeilenvorschub.

Wenn ich das unbenannte Register in das aRegister kopieren möchte, indem ich Folgendes eingebe: :let @a = @"
Hier ist sein Inhalt (Ausgabe von :reg a):

"a   foo^Jbar^J

Es hat sich nicht geändert.

Wenn ich es jetzt durch Eingabe in das Suchregister dupliziere :let @/ = @", ist hier sein Inhalt (Ausgabe von :reg /):

"/   foo^@bar^@

Nach der vorherigen Tabelle scheint ^@es sich um die Caret-Notation für ein Null-Zeichen zu handeln.
Warum wird ein Zeilenvorschub im Suchregister automatisch in ein Nullzeichen umgewandelt (nicht jedoch im aRegister)?

Wenn ich das unbenannte Register in die Befehlszeile (oder in eine Suche danach /) einfüge :<C-R>", wird durch Eingabe Folgendes eingefügt:

:foo^Mbar^M

Auch hier ^Mscheint laut letzter Grafik die Caret-Notation für ein Carriage Return zu sein.
Warum wird ein Zeilenvorschub in der Befehlszeile automatisch in einen Wagenrücklauf umgewandelt?

Bearbeiten :

Normalerweise können Sie ein literales Steuerzeichen einfügen, indem Sie Folgendes eingeben:
<C-V><C-{character in caret notation}>

Sie können beispielsweise ein Literal <C-R>durch Eingabe einfügen <C-V><C-R>.
Sie können es für scheinbar jedes Steuerzeichen tun.
Allerdings ist mir aufgefallen, dass ich kein Literal LF in einen Puffer oder in die Befehlszeile einfügen kann. Wenn ich <C-V><C-J>Folgendes ^@eingebe, wird anstelle von ein Nullzeichen eingefügt ^J.
Ist es der gleiche Grund, warum ein LF im Suchregister in NUL umgewandelt wird?

Bearbeiten 2 :

In :h key-notationkönnen wir folgendes lesen:

<Nul>       zero            CTRL-@    0 (stored as 10) <Nul>
<NL>        linefeed        CTRL-J   10 (used for <Nul>)

Der stored as 10Teil in der ersten Zeile und used for <Nul>in der zweiten Zeile könnte darauf hinweisen, dass es eine Art Überlappung zwischen einem LF und einem NUL gibt und dass sie als dasselbe interpretiert werden könnten. Aber sie können nicht dasselbe sein, denn nach dem vorherigen Befehl ausführen :let @/ = @", wenn ich tippe nim normalen Modus zum nächsten Auftreten der zwei Linien zu erhalten foound bar, statt ein positives Spiel bekommen, ich habe die folgende Fehlermeldung:

E486: Pattern not found: foo^@bar^@

Außerdem scheint dieser Link zu erklären, dass ein NUL das Ende einer Zeichenfolge bezeichnet, während ein LF das Ende einer Zeile in einer Textdatei bezeichnet.

Und wenn ein NUL stored as 10wie in der Hilfe angegeben ist, derselbe Code wie für ein LF, wie kann Vim dann den Unterschied zwischen den beiden machen?

Edit 3 :

Möglicherweise werden ein LF und ein NUL mit demselben Dezimalcode codiert 10, wie in der Hilfe angegeben. Und Vim macht dank des Kontexts den Unterschied zwischen den beiden. Wenn es auf ein Zeichen trifft, dessen Dezimalcode sich 10in einem Puffer oder einem Register befindet, mit Ausnahme der Such- und Befehlsregister, wird es als LF interpretiert.
Im Suchregister ( :reg /) wird es jedoch als NUL interpretiert, da Vim im Kontext einer Suche nur nach einer Zeichenfolge sucht, deren Konzept end of line in a filekeinen Sinn ergibt, da es sich bei einer Zeichenfolge nicht um eine Datei handelt (was seltsam ist, da Sie dies können) benutze das Atom immer noch \nin einem Suchmuster, aber vielleicht ist das nur ein Merkmal der Regex-Engine?). Es wird also automatisch 10als NUL interpretiert, weil es das nächste Konzept ist ( end of stringend of line).

Ebenso :reg :interpretiert es in der Befehlszeile / im Befehlsregister ( ) den Code 10als CR, weil das Konzept von end of line in a filehier keinen Sinn ergibt. Das nächste Konzept ist end of commandso Vim interpretiert 10als CR, weil hitting Enterder Weg zu Ende ist / einen Befehl ausführen und eine CR ist die gleiche wie Schlagen Enter, da beim Einfügen eines wörtlichen mit <C-V><Enter>, ^Mangezeigt wird.

Vielleicht 10ändert sich die Interpretation des Zeichens, dessen Code ist , je nach Kontext:

  • Zeilenende in einem Puffer ( ^J)
  • Zeichenfolgeende in einer Suche ( ^@)
  • Befehlsende in der Befehlszeile ( ^M)

2
Manchmal wird das Auftreten unerwarteter NULL Zeichen durch die zugrunde liegende C-Funktion verursacht, die die Zeichenfolgen verarbeitet. Diese Erklärung, wie C verknüpfte Zeichenfolgen verarbeitet , erklärt, dass C Zeichenfolgen intern mit einem abgrenzt NULL. NULLs kommen im Text selten genug vor, um ein gutes Zeichen für diesen Zweck zu sein. Dies hat zur Folge, dass das C-Programm (vim) versucht hat, einen "leeren" String an eine interne C-Funktion zu übergeben
the_velour_fog

2
zB someFunction(arg1, "")wo arg 2 war, "" dh "das Element zwischen den Anführungszeichen, was buchstäblich nichts ist - ein" leeres ". Ein NULL kann erscheinen, weil es von der zugrunde liegenden C-Implementierung" hinzugefügt "wurde, da es die Zeichenfolge begrenzte. Ich weiß nicht wie würden Sie dies überprüfen - aber es kommt als mögliche Ursache in den Sinn.
the_velour_fog

1
Siehe auch die Diskussion über \rund den \nUnterschied in:substitute .
Jamessan

Antworten:


4

Zunächst einmal vielen Dank für diesen sehr umfassenden und nachdenklichen Beitrag.

Nach einigen Tests bin ich zu folgendem Schluss gekommen:

  1. Steuerzeichen werden in der Caret-Notation angezeigt: ^Mfür <CR>(Wagenrücklauf) und ^Jfür <LF>(Zeilenvorschub). In Puffern werden <EOL>(Zeilenende) als neue Bildschirmzeilen angezeigt und mit der Eingabetaste eingegeben. <EOL>hängen vom Dateiformat des Puffers ab: <EOL> = <CR>|<LF>|<CR><LF>für mac|unix|dos.

  2. Beim Bearbeiten eines Puffers wird immer das Dateiformat eingestellt. Um das Dateiformat eines geöffneten Puffers zu ändern, können Sie den folgenden Befehl verwenden, der konvertiert <EOL>:

    :set f[ile]f[ormat]=mac|unix|dos
    

    Zusätzlich zum Umwandeln <EOL>dieses Befehl konvertiert , <LF>um , <CR>wenn das Dateiformat aus Wechsel maczu unix|dos, und umgekehrt, <CR>um , <LF>wenn von dem Dateiformatwechsel unix|doszu mac. Um die tatsächlichen Bytes des Puffers anzuzeigen, können Sie den folgenden Befehl verwenden, der die Textdarstellung des Puffers mit dem praktischen Hexadezimal-Editor xxd in seine Hexadezimaldarstellung umwandelt:

    :%!xxd
    
  3. In Registern (mit dem Befehl zeigten :reg[isters]oder :di[splay]), <EOL>werden immer angezeigt , wie ^J(aber nicht alle ^Jsind <EOL>), unabhängig vom Dateiformat des Puffers. Sie <EOL>werden jedoch so gespeichert, wie sie sollten. Um visuell real ^J(das heißt <LF>) von den anderen ^J(das heißt <EOL>) in Registern unterscheiden zu können, können Sie den folgenden Befehl verwenden, mit dem die hexadezimalen Werte anstelle der Caret-Notation von Steuerzeichen angezeigt werden, die sich von den folgenden unterscheiden <EOL>:

    :set d[ispla]y=uhex
    
  4. In Suchmustern und Ersetzungszeichenfolgen:

    \r = newline different from <EOL> (<CR> if <EOL> = <CR><LF>|<LF>, <LF> if <EOL> = <CR>)
    \n = <EOL>
    
  5. Überall:

    <C-V><C-M>|<C-V><EOL> = newline different from <EOL>
    <C-V><C-J> = <NUL>
    

    Dies zeigt, dass im Dateiformat keine dosEingabe möglich ist <LF>, da <EOL> = <CR><LF>und <C-V><C-M>|<C-V><EOL> = <CR>.

  6. In Substitutionszeichenfolgen:

    • Zeilenumbruch anders <EOL>als interpretiert werden <EOL>;

    • <EOL>werden interpretiert als <NUL>.

    Also, nach 4, :%s[ubstitute]/\r/\r/gersetzt jeden Newline unterscheidet sich von <EOL>im Puffer mit <EOL>, während :%s[ubstitute]/\n/\n/gersetzt jeden <EOL>im Puffer mit <NUL>.

  7. Im Fahndungsregister /und Befehlsregister :, <EOL>werden umgewandelt zu

    • Zeilenumbruch anders <EOL>als beim Einfügen aus einem Register mit /<C-R>{register}oder :<C-R>{register};

    • <NUL>wenn sie aus einem Register mit eingelegter :let @/=@{register}oder :let @:=@{register}jeweils.

  8. In Puffern werden andere Zeilenumbrüche <EOL>als konvertiert , <EOL>wenn sie aus einem Register mit eingefügt werden i<C-R>{register}.

Warum wird ein Zeilenvorschub in der Befehlszeile in ein Nullzeichen im Suchregister und in einen Wagenrücklauf umgewandelt?

Bevor Sie <LF>vom unbenannten Register "in andere Register kopieren , müssen Sie es eingeben <LF>und in das Register einfügen ". Wenn das Dateiformat "" ist unix, können Sie dies yyin einer leeren Zeile tun . Wenn das Dateiformat ist mac, können Sie dies mit i<C-V><C-M><Esc>yl; Wenn das Dateiformat ist dos, können Sie keine Daten eingeben <LF>(vgl. 5.).

Jetzt ist deine Aussage teilweise falsch, da

  • Sie verwenden nicht dieselbe Methode zum Kopieren <LF>aus dem Register "in das Suchregister /und das Befehlsregister :. Sie verwenden :let @/=@"zum Kopieren in das Register /und :<C-R>"zum Kopieren in das Register :. Mit /<C-R>"und :<C-R>"erhalten Sie <CR>in beiden Fällen das gleiche Ergebnis ( ).

  • Die Konvertierungen <LF>davon finden mit Ihren zwei verschiedenen Kopiermethoden nur statt, wenn das Dateiformat ist unix. Wenn dies der Fall ist mac, <LF>wird beim Kopieren in das Register oder das Register nicht konvertiert , und wenn dies der Fall ist , können Sie nicht einmal Eingaben vornehmen ./:dos<LF>

Die richtige Aussage ist von 7. Aber die Gründe dafür kenne ich wirklich nicht.


Warum ist das so schwer zu verstehen ... Ich habe in mehreren Beiträgen über SO und VIM-SE und VIM-Hilfe recherchiert, aber nicht vollständig konsistent und immer noch verwirrt.
Violapterin
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.