Vim: s substitui as primeiras ocorrências de N g em uma linha

11

No vim, às vezes tenho a oportunidade de substituir as primeiras ocorrências de uma correspondência em uma linha, mas nem todas como g . por exemplo:

a a a a a

para

b b b a a

Eu sei que eu poderia usar :s/a/b/[enter]:[up][enter]:[up][enter] , mas isso é tedioso o suficiente em três repetições, eu tenho linhas com potencialmente 10 + substituições. Eu tentei:

  • :s/a/b/3g : vim queixou-se de caracteres finais.
  • :s/a/b/3 : altera a primeira ocorrência desta e das duas linhas seguintes.
  • 3:s/a/b : igual ao anterior.
  • :s/a/b/g3 : altera todas as ocorrências nesta e nas próximas duas linhas.
  • :3s/a/b : altera a primeira ocorrência na linha 3.
  • :/a/,3/a/s/a/b : altera a primeira ocorrência em cada linha entre o próximo a e a terceira linha contendo a no arquivo (solicitando a reversão, se necessário).
  • :/a/,/\([^a]*a\)\{3\}/s/a/b/ : altera a primeira ocorrência em cada linha entre esta e a próxima com 3 a s (e isso não teria sido facilmente extensível a uma pesquisa com vários caracteres).

E vários outros padrões de endereçamento, nenhum dos quais funcionou. Devo dizer que aprendi bastante sobre o comando :s tentando encontrar uma resposta para esse problema, mas ainda não o resolvi.

Alguém sabe como fazer isso?

(pontos de bônus para um intervalo específico, por exemplo, de segunda a quarta ocorrências)

    
por Kevin 19.12.2011 / 19:23

3 respostas

9

Aproveitando a ideia de :s/pattern/replacement/gc de Samus_ (que parece ser a maneira mais simples de garantir a operação correta quando o padrão está contido na string de substituição), para substituir a segunda a quarta ocorrências em uma única linha:

:call feedkeys("nyyyq") | s/pat/string/gc

feedkeys() é uma função que insere a cadeia de entrada na fila de entrada do teclado. O objetivo é fazer a contagem adiantada para que você não tenha que se preocupar em perder ou ser interrompido.

Para um caso mais geral, substituir o Mth por meio de Nth ocorrências em uma única linha para N maior ou igual a um muito grande M :

:call feedkeys(repeat("n", M-1) . repeat("y", N-M+1) . "q") | s/pat/string/gc

Substitua M e N pelos valores desejados (você pode até mesmo deixar vim fazer a aritmética mental trivial se não quiser fazer isso sozinho) . Observe que . é o operador de concatenação de cadeias de caracteres do VimL. Obviamente, isso só salva as teclas digitadas para grandes M . Se você usar essa funcionalidade com freqüência, poderá poupar tempo para colocar o acima em um comando personalizado ou função de algum tipo, pois é um pouco para digitar.

    
por 24.01.2012 / 17:18
7

Para a primeira pergunta que gostaria de fazer:

:s/a/b
&&

O segundo é mais complicado, eu não sei como fazer isso automaticamente, mas você pode fazer o vim perguntar a você em cada partida assim:

:s/a/b/gc

Então você responde "não" às primeiras n correspondências e "sim" às outras.

    
por 20.12.2011 / 17:40
6
a a a a a
a a a a a
a a a a a
a a a a a
a a a a a
a a a a a
a a a a a

:3,6g/^/let i=0 | while i<3 | s/a/b/ | let i+=1 | endwhile

a a a a a
a a a a a
b b b a a
b b b a a
b b b a a
b b b a a
a a a a a
    
por 20.12.2011 / 13:31