Você precisa de substituição por um estado. Lembro-me de ter fornecido uma (/ várias?) Solução completa para esse tipo de problemas no SO.
Aqui está outra maneira de proceder (1). Agora, vou prosseguir em 2 etapas:
- uma variável de lista fictícia que preciso para o truque sujo e complicado que vou empregar
- uma substituição na qual insiro o len desse array fictício que estou preenchendo em cada ocorrência correspondente.
Que dá:
:let t=[]
:%s/#\zs\d\+\(\.\d\+\)\=\ze/\=len(add(t,1))/g
Se você não está acostumado a vim regexes, eu uso :h /\zs
e \ze
para especificar qual sub-padrão eu estou correspondendo, então eu correspondo a uma série de dígitos possivelmente seguidos por um ponto e outros dígitos. Isso não é perfeito para nenhum número de ponto flutuante, mas é o suficiente aqui.
Nota: Você precisará agrupá-lo em uma função dupla + comando para uma interface simples. Novamente, existem exemplos no SO / vim ( aqui , aqui , aqui ) Atualmente, conheço o suficiente do vim para não me importar em envolver esse truque em um comando. Na verdade, poderei escrever este comando na primeira tentativa, enquanto levarei alguns minutos para lembrar o nome do comando.
(1) O objetivo é poder manter um estado entre substituições e substituir a ocorrência atual por algo que dependa do estado atual.
Graças a :s\=
nós somos capazes de inserir algo resultante de uma computação.
Continua sendo o problema do estado. Ou definimos uma função que gerencia um estado externo ou nos atualizamos como um estado externo. Em C (e idiomas relacionados), poderíamos ter usado algo como length++
ou length+=1
. Infelizmente, nos scripts do vim, +=
não pode ser usado imediatamente. Ele precisa ser usado com :set
ou com :let
. Isso significa que :let length+=1
incrementa um número, mas não retorna nada. Nós não podemos escrever :s/pattern/\=(length+=1)
. Precisamos de outra coisa.
Precisamos de funções mutantes. ou seja, funções que modificam suas entradas. Temos setreg()
, map()
, add()
e provavelmente mais. Vamos começar com eles.
setreg()
muda um registro. Perfeito. Podemos escrever setreg('a',@a+1)
como na solução do @Doktor OSwaldo. E, no entanto, isso não é suficiente. setreg()
é mais um procedimento do que uma função (para aqueles que conhecem Pascal, Ada ...). Isso significa que não retorna nada. Na verdade, ele retorna algo. Saída nominal (ou seja , saídas não-excepcionais ) sempre retorna algo. Por padrão, quando esquecemos de retornar algo, 0 é retornado - isso também se aplica às funções internas. É por isso que em sua solução a expressão de substituição é realmente \=@a+setreg(...)
. Complicado, não é?
map()
também pode ser usado. Se começarmos de uma lista com um único 0 ( :let single_length=[0]
), poderemos incrementá-la graças a map(single_length, 'v:val + 1')
. Então precisamos retornar o novo comprimento. Ao contrário setreg()
, map()
retorna sua entrada mutada. Perfeito, o comprimento é armazenado na primeira (e única e, portanto, última) posição da lista. A expressão de substituição pode ser \=map(...)[0]
.
add()
é o que eu costumo usar por hábito (eu pensei sobre isso map()
na verdade, e ainda não participei das respectivas apresentações). A idéia add()
é usar uma lista como o estado atual e acrescentar algo no final antes de cada substituição. Costumo armazenar o novo valor no final da lista e usá-lo para a substituição. Como add()
também retorna a sua lista de entrada mutante, podemos usar: \=add(state, Func(state[-1], submatch(0)))[-1]
. No caso do OP, precisamos apenas lembrar quantas correspondências foram detectadas até o momento. Retornar o comprimento dessa lista de estados é suficiente. Daí meu \=len(add(state, whatever))
.
perldo
, você pode usar:%perldo s/#\K\d+(\.\d+)?/++$i/ge