Por que a substituição de novas linhas usando g / re / p se aplica apenas a todas as outras linhas no Vim?

3

Considere:

foo
bar
....
bar
baz

Então:

:g/bar/s/\n/\r\r/g

inesperadamente retorna:

foo
bar

bar
bar

bar
bar

...
baz

quando quero novas linhas após cada bar . Ainda:

:g/bar/p

retorna:

bar
bar
...
bar

como esperado e se houver novas linhas entre todos os bar s, recebo o que espero - uma nova linha extra após cada linha contendo bar . Eu resolvi o problema por meio de:

:%s/\(bar.*\)\n/\r\r/g

mas eu gostaria de ter uma melhor compreensão do que está acontecendo.

    
por gvkv 08.09.2010 / 20:47

2 respostas

8

Para entender o que está acontecendo nesse nível de detalhe, acho que você precisa alcançar o código-fonte. Então, citando vim-7.1.314/src/ex_cmds.c (comentário na cabeça da definição de ex_global() ):

This is implemented in two passes: first we scan the file for the pattern and set a mark for each line that (not) matches. secondly we execute the command for each line that has a mark. This is required because after deleting lines we do not know where to search for the next match.

Assim, se você excluir uma linha no comando :g 'ed, a marca dessa linha também desaparecerá. Se você criar uma linha no comando :g 'ed, ela não será marcada, portanto, o comando não será executado nela. No seu exemplo, a linha 3 é unida à linha 2, então a marca na linha 3 desaparece, e a próxima marca após a linha 2 é a originalmente colocada na linha 4.

Além disso, ex_global define a variável global_busy , o que faz com que alguns comandos, incluindo :s , tenham um comportamento um pouco diferente. Eu não acho que a diferença seja relevante aqui.

    
por 08.09.2010 / 22:53
3

Gilles respondeu o seu" porquê? ", mas eu pensei que você poderia estar interessado em uma maneira mais simples de fazer o que você queria.

I want newlines after every bar.

Em vez de substituir o caractere de terminação de linha (juntando as linhas e perdendo a marca interna, por resposta de Gilles), adicione uma linha em branco logo antes do final de cada linha correspondente. Use $ para obter uma correspondência de largura zero logo antes do final da linha e insira uma quebra de linha (também não é necessário o modificador /g , pois o padrão corresponderá apenas uma vez por linha).

:g/bar/s/$/\r/
    
por 09.09.2010 / 07:50

Tags