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.

couldwasiereisawelba
fonte

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.

djjcast
fonte
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
jjaderberg
fonte
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.

fruglemonkey
fonte
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.

kba fica com Monica
fonte
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.

Vitor
fonte
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