Como substituir um caractere por uma nova linha no Vim

1967

Estou tentando substituir cada um ,no arquivo atual por uma nova linha:

:%s/,/\n/g 

Mas ele insere o que parece ser uma ^@nova linha real. O arquivo não está no modo DOS nem nada.

O que devo fazer?

Se você estiver curioso, como eu, verifique a pergunta Por que a nova linha do Vim é? também.

Vinko Vrsalovic
fonte
2
Stack Overflow é um site para perguntas sobre programação e desenvolvimento. Esta questão parece estar fora de tópico, porque não se trata de programação ou desenvolvimento. Consulte Quais tópicos posso perguntar aqui na Central de Ajuda. Talvez o Superusuário ou o Unix e Linux Stack Exchange sejam um lugar melhor para perguntar.
jww 20/05/19
5
@jww esta pergunta tem 10 anos ... parece ser muito antiga para migrar. Existem muitas perguntas como esta, por exemplo: stackoverflow.com/questions/10175812/…
Vinko Vrsalovic 20/18
14
O @jww vim é uma ferramenta comumente usada por programadores, e as perguntas sobre ferramentas comumente usadas por programadores estão no tópico Stack Overflow . Embora obviamente isso seja mais adequado no Vi e no Vim .
user202729

Respostas:

2565

Use em \rvez de \n.

Substituindo por \ninsere um caractere nulo no texto. Para obter uma nova linha, use \r. Ao procurar uma nova linha, você ainda usaria \n. Essa assimetria se deve ao fato de que \ne \r fazer coisas ligeiramente diferentes :

\n corresponde ao final da linha (nova linha), enquanto \r corresponde ao retorno de carro. Por outro lado, em substituições \ninsere um caractere nulo, enquanto \rinsere uma nova linha (mais precisamente, é tratada como entrada <CR>). Aqui está um pequeno exemplo não interativo para ilustrar isso, usando o recurso de linha de comando do Vim (em outras palavras, você pode copiar e colar o seguinte em um terminal para executá-lo). xxdmostra um hexdump do arquivo resultante.

echo bar > test
(echo 'Before:'; xxd test) > output.txt
vim test '+s/b/\n/' '+s/a/\r/' +wq
(echo 'After:'; xxd test) >> output.txt
more output.txt
Before:
0000000: 6261 720a                                bar.
After:
0000000: 000a 720a                                ..r.

Em outras palavras, \ninseriu o byte 0x00 no texto; \rinseriu o byte 0x0a.

Konrad Rudolph
fonte
127
/ r é tratado como pressionar a tecla Enter / Return. Funciona em todas as plataformas.
Luka Marinko
73
Consulte também Por que a nova linha do Vim é \ ra? .
Andrew Marshall
14
Eu gostaria que isso funcionasse para o clássico vi. No AIX v6.1, \rnão funciona assim. Mas você pode pressionar Ctrl-V Enterno lugar da digitação \re funciona.
eksortso
3
Estou atrasado para a festa. Se \rinsere <CR>e \ninsere um valor nulo, como eu substituiria algo por um retorno de carro?
Sr. Llama
2
@SunnyRaj você tem certeza sobre a história da CR e da LF? Tive a impressão de que originalmente a LF moveu o papel uma linha para frente, mas não moveu o cabeçote de impressão, e CR moveu o cabeçote de impressão, mas não moveu o papel. Como resultado, se o seu sistema operacional não converter a entrada antes da impressão, você não poderá usar apenas LF ou CR para obter a saída correta. O MS DOS usou dados brutos da impressora como formato de arquivo de texto, o Mac OS usou CR e converteu-os para o formato bruto da impressora e o UNIX usou LF e os converteu para o formato bruto da impressora.
Mikko Rantalainen
210

Aqui está o truque:

Primeiro, defina sua sessão Vi (m) para permitir a correspondência de padrões com caracteres especiais (por exemplo: nova linha). Provavelmente vale a pena colocar esta linha no seu arquivo .vimrc ou .exrc:

:set magic

Em seguida, faça:

:s/,/,^M/g

Para obter o ^Mpersonagem, digite Ctrl+ Ve pressione Enter. No Windows, façaCtrl + Q, Enter. A única maneira de me lembrar disso é lembrando o pouco sentido que eles fazem:

UMA: Qual seria o pior caractere de controle usado para representar uma nova linha?

B: Ou q(porque isso normalmente significa "Quit") ou vporque seria tão fácil de digitar Ctrl+C por engano e matar o editor.

A: Faça isso.

Logan
fonte
9
Estou usando o GVim no Windows e não preciso do :set magic(não está no meu ~ / _vimrc) nem ctrl-q. Apenas um simples ctrl-vseguido de enter cria o ^Mpersonagem para mim.
22411 Chris Phillips
5
Cv não representa uma nova linha; é o comando "escape next literal character". Não sei o que é um mnemônico para o Cv, mas há uma razão para ele não mapear mentalmente para a nova linha.
Jim Stewart
27
Ctrl-v é um mnemônico para "literalmente" - ou seja, a tecla escape seguinte pressionada em seu código / caractere "literal". No Windows, é colar: para manter as coisas familiares. Ctrl-Q é para "(des) Citação" talvez. Bastante estúpido, de qualquer maneira - mas você pode usá-lo em arquivos binários - por exemplo, para procurar por Ctrl-A a Ctrl-Z (Ascii 1-26, eu acho).
Tomasz Gandor,
1
Ctrl-Cna verdade, não mata o editor, embora possa cancelar você de volta ao modo Normal. Ctrl-Vsignifica literalmente e Ctrl-Qsignifica que alguém cometeu o erro de carregar o $VIMRUNTIME/mswin.vimarquivo de configuração. Você não precisa de mswin. Basta usar seu próprio vimrc.
00dani
Uau isso é incrível. Eu costumava fazer sed -n l até agora. É bom saber que o mesmo pode ser alcançado com o Ctrl-vvim.
arpit
98

Na sintaxe s/foo/bar, \re \ntêm significados diferentes, dependendo do contexto.


Baixo:

Para foo:

\ n = nova linha (LF no Linux / Mac, CR + LF no Windows)
\ r = retorno de carro (CR)

Para bar:

\ r = é nova linha
\ n = byte nulo.

Mais (com números ASCII):

NUL= 0x00 = 0 = Ctrl+ @
LF= 0x0A = 10 = Ctrl+ J
CR= 0x0D = 13 = Ctrl+M

Aqui está uma lista dos caracteres de controle ASCII . Insira-os no Vim via Ctrl+ V, Ctrl+ ---key---.

No Bash ou nos outros shells Unix / Linux, digite Ctrl+---key--- .

Experimente Ctrl+ Mno Bash. É o mesmo que bater Enter, pois o shell percebe o que se entende, mesmo que os sistemas Linux usem feeds de linha para delimitar linhas.

Para inserir literais no bash, anexá-los com Ctrl+ Vtambém funcionará.

Experimente no Bash:

echo ^[[33;1mcolored.^[[0mnot colored.

Isso usa seqüências de escape ANSI . Insira os dois ^[via Ctrl+ V,Esc .

Você também pode tentar Ctrl+ V, Ctrl+ M, Enterque lhe dará o seguinte:

bash: $'\r': command not found

Lembre o \r de cima? :>

Essa lista de caracteres de controle ASCII é diferente de uma tabela de símbolos ASCII completa , pois os caracteres de controle inseridos em um console / pseudoterminal / Vim viaCtrl tecla (haha) podem ser encontrados lá.

Enquanto em C e na maioria dos outros idiomas, você geralmente usa os códigos octais para representar esses 'caracteres'.

Se você realmente quer saber de onde tudo isso vem: O TTY desmistificado . Este é o melhor link que você encontrará sobre esse tópico, mas cuidado: existem dragões.


TL; DR

Normalmente foo= \ne bar= \r.

sjas
fonte
1
Então, eu estou intrigado como você substituir um personagem com um retorno de carro
codeshot
2
@codeshot :s/x/^M/gdeve fazer. Insira a ^Mvia ctrl-vseguida por ctrl-m.
sjas
3
Obrigado sjas, você sabe que esta pergunta é uma das mais estranhas de todos os tempos. 1008 votos para a resposta que basicamente diz nada mais do que "o vim faz o que você encontrou. Isso ocorre porque o vim faz o que você encontrou. Nunca esqueça que o vim faz o que você encontrou." Eu esperava encontrar uma lista restrita de códigos para caracteres interessantes no padrão, na substituição e no motivo da estranheza, para que seja fácil lembrar e prever outras estranhezas semelhantes. Isso teria meu voto.
codeshot
@codeshot uma lista de caracteres de controle ascii pode ajudá-lo. Consulte cs.tut.fi/~jkorpela/chars/c0.html para obter mais referências. Vou atualizar minha resposta para incluir dois links.
sjas
55

Você precisa usar:

:%s/,/^M/g

Para obter o ^Mpersonagem, pressione Ctrl+ vseguido de Enter.

dogbane
fonte
4
Eu tenho que fazer <Cv> <Cm> para obter o caractere ^ M.
Jezen Thomas #
39

\r pode fazer o trabalho aqui para você.

Lasar
fonte
24

Com o Vim no Windows, use Ctrl+ Qno lugar de Ctrl+ V.

grantc
fonte
16

Esta é a melhor resposta para o meu modo de pensar, mas teria sido melhor em uma tabela:

Por que uma nova linha para o Vim?

Então, reformulando:

Você precisa \rusar um avanço de linha (ASCII 0x0A, a nova linha Unix) em uma substituição de regex, mas isso é peculiar à substituição - normalmente você deve continuar esperando o uso \nde avanço de linha e \rretorno de carro.

Isso ocorre porque o Vim foi usado \nem um substituto para significar o caractere NIL (ASCII 0x00). Em \0vez disso, você poderia esperar que o NIL estivesse liberando \nseu uso usual para o avanço de linha, mas \0já tem um significado nas substituições de expressões regulares, portanto foi alterado para \n. Portanto, indo além, também mude a nova linha de \npara \r(que em um padrão regex é o caractere de retorno de carro, ASCII 0x0D).

Personagem | Código ASCII | Representação C | Regex partida | Substituição de Regex
------------------------- + ------------ + ----------- ------- + ------------- + ------------------------
nada | 0x00 \ 0 \ 0 \ n
avanço de linha (nova linha Unix) | 0x0a \ n | \ n | \ r
retorno de carro | 0x0d \ r | \ r | <desconhecido>

NB: ^M( Ctrl+ V Ctrl+ Mno Linux) insere uma nova linha quando usada em uma substituição de regex em vez de um retorno de carro, como outros recomendaram (eu apenas tentei).

Observe também que o Vim converterá o caractere de avanço de linha quando ele for salvo em um arquivo com base em suas configurações de formato de arquivo e isso pode confundir assuntos.

codeshot
fonte
11

No Eclipse , os ^Mcaracteres podem ser incorporados em uma linha e você deseja convertê-los em novas linhas.

:s/\r/\r/g
rickfoosusa
fonte
8

Mas se alguém tiver que substituir, o seguinte funcionará:

:%s/\n/\r\|\-\r/g

Acima, todas as próximas linhas são substituídas pelas próximas e, em seguida, |-uma nova linha. Isso é usado nas tabelas wiki.

Se o texto for o seguinte:

line1
line2
line3

É alterado para

line1
|-
line2
|-
line3
Kiran K Telukunta
fonte
7

Se você precisar fazer isso para um arquivo inteiro, também me foi sugerido que você poderia tentar na linha de comando:

sed 's/\\n/\n/g' file > newfile
Evan Donovan
fonte
1
Observe que isso requer o GNU sed. Tente printf 'foo\\nbar\n' | sed 's/\\n/\n/g'ver se funcionará no seu sistema. (Crédito para o bom povo de #bash na freenode para esta sugestão.)
Evan Donovan
Sim, mas a pergunta era sobre o Vim. Há uma pergunta sobre estouro de pilha Como posso substituir uma nova linha (\ n) usando sed? .
Peter Mortensen
5

Aqui está a resposta que funcionou para mim. Desse cara:

---- citação Use o editor vi para inserir um novo caractere de linha em substituir


Outra coisa que tenho que fazer e não consigo me lembrar e depois tenho que olhar para cima.

No vi, para inserir um caractere de nova linha em uma pesquisa e substituir, faça o seguinte:

:%s/look_for/replace_with^M/g

O comando acima substitui todas as instâncias de "look_for" por "replace_with \ n" (com \ n significa nova linha).

Para obter o “^ M”, digite a combinação de teclas Ctrl+ Ve depois (solte todas as teclas) pressione a Entertecla.


Peter Mortensen
fonte