Como copiar cada linha 11 vezes, incrementando o último "1" em cada linha de 2 a 12


9

Eu tenho várias linhas em um arquivo e gostaria de copiar cada linha 11 vezes (transformando cada linha em 12 linhas) e incrementar o último "1" em cada linha para que as 12 linhas tenham "1" a " 12 ", onde o" 1 "estava inicialmente. Pode haver outras ocorrências de "1" em cada linha, mas o "1" que eu quero incrementar sempre será a última ocorrência em cada linha. Outra maneira de ver é que o último "1" é sempre depois de "/ nt /" - como em "/ nt / 1" (e sempre será a única ocorrência de "/ nt / 1" em cada linha) .

Então, por exemplo, se eu tiver:

1stlineblahblahblah/nt/1blah
2ndlineblahblahblah/nt/1blah
3rdlineblahblahblah/nt/1blah

Eu quero transformá-lo em:

1stlineblahblahblah/nt/1blah
1stlineblahblahblah/nt/2blah
1stlineblahblahblah/nt/3blah
1stlineblahblahblah/nt/4blah
1stlineblahblahblah/nt/5blah
1stlineblahblahblah/nt/6blah
1stlineblahblahblah/nt/7blah
1stlineblahblahblah/nt/8blah
1stlineblahblahblah/nt/9blah
1stlineblahblahblah/nt/10blah
1stlineblahblahblah/nt/11blah
1stlineblahblahblah/nt/12blah
2ndlineblahblahblah/nt/1blah
2ndlineblahblahblah/nt/2blah
2ndlineblahblahblah/nt/3blah
...

Eu já havia encontrado o comando:

:for i in range(0,12) | put ='1stlineblahblahblah/nt/'.i.'blah' | endfor

funciona para esse fim, mas eu teria que executar manualmente esse comando para cada linha e digitar cada linha (ou copiar e colar) pessoalmente. Existe uma maneira de pegar as linhas que já estão no arquivo e apenas executar um comando que transforma cada linha em doze, da maneira que descrevi?

Agradeço antecipadamente a quem puder me ajudar com isso. Eu também queria apenas observar que esta é a minha segunda pergunta aqui e fiquei satisfeito por ter conseguido várias soluções rápidas e eficazes para a minha primeira pergunta, pela qual eu sou muito grata.

Respostas:


8

Aqui está uma substituição que resolve o problema:

:%s/\(.*\)1\(.*\)/\=join(map(range(1, 12), 'submatch(1) . v:val . submatch(2)'), "\n")

A substituição corresponde a cada linha que contém "1" e captura o texto antes {c1}e depois {c2}do último "1". Para cada linha correspondida, o intervalo de números de um a doze {n}é mapeado para criar doze linhas do formulário {c1}{n}{c2}. Cada grupo de doze linhas substitui sua linha associada, originalmente correspondida.

Veja :h sub-replace-expression.


2
Uau, ótimo comando de uma linha. Lembro que você também encontrou uma solução elegante de uma linha para a primeira pergunta que fiz há algumas semanas. Muito bom trabalho. Muito obrigado. Além disso, acho que há uma maneira de colocar isso no arquivo _vimrc para que eu possa executar um comando ou função fácil de lembrar sem digitar a linha inteira acima (ou ter que rolar pela lista de comandos anteriores), mas Ainda não estou familiarizado o suficiente com a sintaxe _vimrc para saber como fazê-lo.
ablewasiereisawelba

10

Você poderia fazer isso

  1. gravar uma macro e depois
  2. usando o globalcomando ex para executar o número de macro n vezes para cada linha do arquivo.

Depois de gravar a macro, desfaça as alterações feitas durante a gravação, ou haverá n + 1 linhas adicionais para a primeira linha e n para linhas consecutivas.

Grave a macro no aregistro com

qayyp$?\d<CR><C-A>q

Isso registra no register a( qa...q) o seguinte comando:

  • yyp: duplicar a linha atual
  • $: mover para o final da linha
  • ?\d<CR>: pesquise um dígito para trás
  • <C-A>: incrementa o dígito sob o cursor em um

Quando a macro é gravada, remova as alterações feitas durante a gravação, desfazendo ( uu) ou excluindo a linha atual ( dd). Em seguida, repita a macro 11(ou qualquer número de) vezes para cada linha do arquivo com o comando global:

:g//normal 11@a

2
Funcionou! Muito bom obrigado. Inicialmente, tive um problema com o Ctrl-a destacando tudo em vez de adicionar, porque estou usando o gVim no Windows ... mas fiz uma pesquisa rápida e encontrei esse segmento - stackoverflow.com/questions/289681/… - onde eu usei a sugestão de colocar nnoremap <kPlus> <Ca> nnoremap <kMinus> <Cx> no _vimrc para que eu possa usar as teclas "+" e "-" para adicionar e subtrair. Além disso, o comando global precisava ser: g // 11 @ a normal para mim, mas isso foi facilmente descoberto. Obrigado!
ablewasiereisawelba

6

Dois caminhos:

Use uma macro!

Começando com

1stlineblahblahblah/nt/1blah
2ndlineblahblahblah/nt/1blah
3rdlineblahblahblah/nt/1blah

Com o cursor na primeira linha

qqyyp$?\d<CR><Ctrl-a>q
10@q

O que faz:

qq Comece a gravar uma macro no registro q

yyp puxe a linha atual e cole-a abaixo

$?\d<CR> Vá para o final da linha e encontre o primeiro dígito olhando para trás

<Ctrl-a> Incrementar o número

q Pare de gravar a macro.

Isso deixa você com:

1stlineblahblahblah/nt/1blah
1stlineblahblahblah/nt/2blah
2ndlineblahblahblah/nt/2blah
2ndlineblahblahblah/nt/3blah

Com o cursor na segunda linha. Simplesmente repita essa macro quantas vezes desejar (por exemplo, repita-a dez vezes com 10 @ q). Se você deseja automatizar esse processo para cada linha, execute-o globalmente em cada linha:

:g//normal 11@q

Como alternativa, com uma versão mais recente do vim: cole a linha desejada, quantas vezes, bloco visual selecione o dígito que deseja incrementar e pressione g <Ctrl-a>. Isso deve incrementar todos os números no bloco visual conforme desejado. Este é um processo mais manual, no entanto.


11
Incrível, eu não sabia sobre o g <c-a>caminho. Obrigado por compartilhar.
kba fica com Monica

11
@fruglemonkey A primeira parte da sua resposta é igual à acima, mas, no entanto, obrigado. A segunda parte, acho que não funciona para mim (a menos que eu esteja fazendo algo errado), então não devo estar usando a versão correta.
ablewasiereisawelba

5

Acho mais fácil usar macros para tarefas únicas como essa. Basta começar a gravar uma macro com o qnome + do registro e executar a tarefa uma vez. Eu vejo uma tarefa repetível aqui:

  • Selecione a linha
  • puxão
  • colar (colocará você na próxima linha)
  • ir para o fim da linha
  • volte uma palavra
  • incrementar em um

Agora grave as teclas necessárias para registrar a, no modo normal:

qayyp$b<c-a>.

Exclua a linha novamente para testar se a execução da macro 11 vezes produz o resultado correto para uma linha:

11@a

Faz! Então, vamos desfazer novamente e automatizar todo o processo em uma segunda macro b:

qb11@aj

Agora você pode executar @baté o final do arquivo e deve produzir a saída desejada. Parece complicado, mas realmente não é assim que você está acostumado com os padrões de edição típicos.


Não tenho certeza se estou fazendo algo errado, mas não parece estar funcionando. Eu segui o que você escreveu, mas talvez eu tenha entendido algo errado ou não tenha executado algo corretamente. (Estou obtendo o primeiro número da linha incrementado, não o último número da linha.) Obrigado por responder.
ablewasiereisawelba

3
Eu acho que a primeira macro deveria ser qaVyp$b<c-a>. Ou melhor, apenas qayyp$b<c-a>.
Karl Yngve Lervåg 17/02

11
Obrigado, @ KarlYngveLervåg, você está certo, eu consertei a macro.
Kba fica com Monica

2
. Argh :( obrigado por ser @ablewasiereisawelba completa Eu acho que a macro qqyyp$?\d<CR><Ctrl-a>qpor @fruglemonkey e @jjaderberg é melhor, uma vez que procura o último número que eu vou mudá-lo para ser completo..
kba está com Monica

2
@kba Eu apenas pensei que se alguém dedicar tempo e esforço para responder à minha pergunta, eu poderia pelo menos tentar a solução dele - mesmo se eu já tivesse encontrado uma solução funcional de outra pessoa. Agradeço seu esforço - e se isso te faz sentir melhor, você ainda está muito à minha frente. :)
ablewasiereisawelba

2

Salve a macro a seguir e use-a para cada linha:

qqyy11p/\/\zs1<CR><C-v>10jg<C-a>q

A principal diferença em relação às outras respostas é que isso faz uso de g<C-a>uma seleção de coluna que incrementa cada linha com um número diferente. Verifique :help v_g_CTRL-Apara mais informações. Também usei \zspara selecionar a posição inicial do padrão, de modo que o cursor pare no número após a pesquisa.

Observe que você precisa de uma versão recente do Vim para que isso funcione.


11
O @fruglemonkey propôs isso também . É um recurso interessante, embora seja relativamente recente (pelos padrões vim), desde 7.4.754, que ainda não foi enviado para todas as distros.
Kba fica com Monica

Perdeu desculpe
Vitor

11
@Vitor Eu apenas tenho o gVim 7.4, então acho que não posso fazer o g<C-a>que @fruglemonkey e você mencionou, mas obrigado por responder. Devo observar que ao tentar sua macro - pouco antes de chegar à g<C-a>parte, não é o último caractere "1" que estou procurando incrementar que é destacado em bloco, mas, em vez disso, é o caractere antes do primeiro "1 "personagem que é destacado em bloco. (Além disso, eu acho que teria que ser yy11pe 10jno macro, desde que eu estou olhando para adicionar 11 linhas - para um total de 12.)
ablewasiereisawelba

11
Obrigado pelo seu feedback! Atualizei a resposta de acordo. Decidi usar \zs, mas eu poderia simplesmente adicionar um ldepois <CR>.
Vitor

11
Você provavelmente tem algumas configurações no vimrc que afetam a pesquisa de expressões regulares. Tente novamente iniciando o Vim com vim -u NONE. Acabei de fazer isso e isso funciona perfeitamente! De fato, não há como a pesquisa corresponder ao primeiro 1 porque requer uma barra anterior.
Vitor
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.