Perché un avanzamento riga viene convertito in un carattere Null all'interno del registro di ricerca e in un ritorno a capo sulla riga di comando?


12

Se ho il seguente testo:

foo
bar

Lo seleziono visivamente e lo copio.
Il testo è ora memorizzato nel registro senza nome "e qui è il suo contenuto (output di :reg "):

""   foo^Jbar^J

Secondo questo grafico , sembra che ^Jsia la notazione del punto di inserimento per un avanzamento riga.

Se voglio duplicare il registro senza nome nel aregistro digitando: :let @a = @"
Ecco il suo contenuto (output di :reg a):

"a   foo^Jbar^J

Non è cambiato.

Se ora lo duplico nel registro di ricerca digitando :let @/ = @", ecco il suo contenuto (output di :reg /):

"/   foo^@bar^@

Secondo il grafico precedente, sembra che ^@sia la notazione con il cursore per un personaggio Null.
Perché un avanzamento riga viene automaticamente convertito in un carattere Null all'interno del registro di ricerca (ma non nel aregistro)?

Se inserisco il registro senza nome nella riga di comando (o all'interno di una ricerca successiva /), digitando :<C-R>", ecco cosa viene inserito:

:foo^Mbar^M

Ancora una volta, secondo l'ultimo grafico, ^Msembra essere la notazione del punto di inserimento per un ritorno a capo.
Perché un avanzamento riga viene automaticamente convertito in un ritorno a capo sulla riga di comando?

Modifica :

Di solito è possibile inserire un carattere di controllo letterale digitando:
<C-V><C-{character in caret notation}>

Ad esempio, è possibile inserire un valore letterale <C-R>digitando <C-V><C-R>.
Puoi farlo apparentemente per qualsiasi personaggio di controllo.
Tuttavia ho notato che non sono in grado di inserire un LF letterale all'interno di un buffer o sulla riga di comando, perché se digito: <C-V><C-J>inserisce ^@, un carattere null, anziché ^J.
È per lo stesso motivo per cui un LF viene convertito in NUL all'interno del registro di ricerca?

Modifica 2 :

In :h key-notation, possiamo leggere questo:

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

La stored as 10parte sulla prima riga e used for <Nul>sulla seconda riga potrebbe indicare che esiste una sorta di sovrapposizione tra un LF e un NUL e che potrebbero essere interpretati come la stessa cosa. Ma non possono essere la stessa cosa, perché dopo aver eseguito il comando precedente :let @/ = @", se digito nin modalità normale per arrivare alla ricorrenza successiva delle 2 righe fooe bar, invece di ottenere una corrispondenza positiva, ho il seguente messaggio di errore:

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

Inoltre questo collegamento sembra spiegare che un NUL indica la fine di una stringa, mentre un LF indica la fine di una riga in un file di testo.

E se un NUL è stored as 10come dice l'aiuto, che è lo stesso codice di un LF, come fa Vim a fare la differenza tra i 2?

Modifica 3 :

Forse un LF e un NUL sono codificati con lo stesso codice decimale 10, come dice l'aiuto. E Vim fa la differenza tra i 2 grazie al contesto. Se incontra un carattere il cui codice decimale si trova 10in un buffer o in qualsiasi registro, ad eccezione dei registri di ricerca e comando, lo interpreta come LF.
Ma nel registro di ricerca ( :reg /) lo interpreta come un NUL perché nel contesto di una ricerca, Vim cerca solo una stringa in cui il concetto di end of line in a filenon ha senso perché una stringa non è un file (il che è strano dal momento che puoi usi ancora l'atomo \nin un modello cercato, ma forse questa è solo una caratteristica del motore regex?). Quindi interpreta automaticamente 10come NUL perché è il concetto più vicino ( end of stringend of line).

E allo stesso modo, nella riga di comando / registro comandi ( :reg :) interpreta il codice 10come CR, perché qui il concetto di end of line in a filenon ha senso. Il concetto più vicino è end of commandquindi che Vim interpreta 10un CR, perché colpire Enterè il modo di terminare / eseguire un comando e un CR è lo stesso di colpire Enter, poiché quando si inserisce un valore letterale con <C-V><Enter>, ^Mviene visualizzato.

Forse l'interpretazione del personaggio il cui codice è 10cambiato in base al contesto:

  • fine riga in un buffer ( ^J)
  • fine della stringa in una ricerca ( ^@)
  • fine del comando sulla riga di comando ( ^M)

2
A volte il verificarsi di NULL caratteri imprevisti è causato dalla funzione C sottostante che gestisce le stringhe. Questa spiegazione di come C elabora le stringhe che hai collegato spiega che C delimita internamente le stringhe con a NULL. NULLs si verificano abbastanza raramente nel testo da renderlo un buon personaggio per questo scopo. Una conseguenza di ciò è che se il programma C (vim) provasse a passare una stringa "vuota" in una funzione C interna
the_velour_fog

2
es. someFunction(arg1, "")dove arg 2 era "" cioè "l'elemento tra le virgolette, che è letteralmente nulla - un" vuoto ". può apparire un NULL, perché è stato" aggiunto "dall'implementazione C sottostante mentre delimitava la stringa. Non lo so come potresti verificarlo - ma ti viene in mente una possibile causa
the_velour_fog

1
Vedi anche la discussione \re la \ndifferenza in:substitute .
Jamessan,

Risposte:


4

Innanzitutto, grazie per questo post molto esauriente e ponderato.

Dopo alcuni test, sono giunto a questa conclusione:

  1. I caratteri di controllo vengono visualizzati usando la notazione del punto di inserimento: ^Mper <CR>(ritorno a capo) e ^Jper <LF>(avanzamento riga). Nei buffer, <EOL>(fine riga) vengono visualizzati come nuove righe dello schermo e vengono immessi con il tasto Invio. <EOL>dipendono dal formato del buffer: <EOL> = <CR>|<LF>|<CR><LF>per mac|unix|dosrispettivamente.

  2. Quando si modifica un buffer, il formato del file è sempre impostato. Per modificare il formato del file di un buffer aperto, è possibile utilizzare il seguente comando che converte <EOL>:

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

    Oltre alla conversione <EOL>, Questo comando converte <LF>a <CR>quando si cambia il formato del file da maca unix|dos, e viceversa, <CR>per <LF>quando si cambia il formato del file da unix|dosa mac. Per vedere i byte reali del buffer, puoi usare il seguente comando che trasforma la rappresentazione testuale del buffer nella sua rappresentazione esadecimale usando il comodo editor esadecimale xxd:

    :%!xxd
    
  3. Nei registri (mostrati con il comando :reg[isters]o :di[splay]), <EOL>vengono sempre visualizzati come ^J(ma non tutti lo ^Jsono <EOL>), indipendentemente dal formato file del buffer. Tuttavia <EOL>sono memorizzati come dovrebbero. Per essere in grado di distinguere visivamente reale ^J(cioè <LF>) dagli altri ^J(cioè <EOL>) nei registri, è possibile utilizzare il comando seguente che visualizza i valori esadecimali invece della notazione di inserimento dei caratteri di controllo diversi da <EOL>:

    :set d[ispla]y=uhex
    
  4. Nei modelli di ricerca e nelle stringhe di sostituzione:

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

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

    Ciò dimostra che quando il formato del file è dos, è impossibile inserire <LF>, poiché <EOL> = <CR><LF>e <C-V><C-M>|<C-V><EOL> = <CR>.

  6. Nelle stringhe di sostituzione:

    • i newline diversi da <EOL>vengono interpretati come <EOL>;

    • <EOL>sono interpretati come <NUL>.

    Quindi, secondo 4., :%s[ubstitute]/\r/\r/gsostituisce ogni nuova riga diversa da <EOL>nel buffer con <EOL>, mentre :%s[ubstitute]/\n/\n/gsostituisce ogni <EOL>nel buffer con <NUL>.

  7. Nel registro di ricerca /e nel registro dei comandi :, <EOL>vengono convertiti in

    • newline diverso da <EOL>quando inserito da un registro con /<C-R>{register}o :<C-R>{register}rispettivamente;

    • <NUL>quando inserito da un registro con :let @/=@{register}o :let @:=@{register}rispettivamente.

  8. Nei buffer, i newline diversi da <EOL>vengono convertiti in <EOL>quando inseriti da un registro utilizzando i<C-R>{register}.

Perché un avanzamento riga viene convertito in un carattere Null all'interno del registro di ricerca e in un ritorno a capo sulla riga di comando?

Prima di copiare <LF>dal registro senza nome "ad altri registri, è necessario immetterlo <LF>e inserirlo nel registro ". Se il formato del file è unix, puoi farlo usando yyuna riga vuota; se il formato del file è mac, puoi farlo usando i<C-V><C-M><Esc>yl; se il formato del file è dos, non è possibile inserire <LF>(cfr. 5.).

Ora la tua affermazione è parzialmente sbagliata, da allora

  • non si utilizza lo stesso metodo per copiare <LF>dal registro "nel registro di ricerca /e nel registro dei comandi :. Si utilizza :let @/=@"per la copia nel registro /e :<C-R>"per la copia nel registro :. L'uso di /<C-R>"e :<C-R>"rispettivamente ti darà lo stesso risultato ( <CR>) in entrambi i casi;

  • le conversioni di <LF>ciò avvengono con i tuoi due diversi metodi di copia avvengono solo quando il formato del file è unix. In tal caso mac, non<LF> viene convertito quando viene copiato nel registro o nel registro e, in caso affermativo , non è nemmeno possibile immettere ./:dos<LF>

La dichiarazione giusta è data da 7. Ma non conosco davvero i motivi che stanno dietro.


Perché è così difficile da capire ... Ho studiato diversi post su SO e vim-SE e aiuto di vim, ma non del tutto coerenti e ancora confusi.
Violapterin,
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.