Excluir n linhas pular script de 1 linha

10

Eu quero criar um script básico do Vim que simplesmente exclua n linhas, pule 1 linha e repita até o final do documento. Não ligo para correspondências específicas, só quero excluir a linha. Por exemplo; Então, eu quero repetir o comando 3ddjpara todo o documento.

Text I want to keep.   
Text I want to delete.  
Text I want to delete.  
Text I want to delete.  
Text I want to keep.  
Text I want to delete.  
Text I want to delete.  
Text I want to delete.  
Text I want to keep.  
Text I want to delete.  
Text I want to delete.  
Text I want to delete.   

Então parece que ...

Text I want to keep.  
Text I want to keep.  
Text I want to keep.  

Obrigado.

Max Copley
fonte
Você incluiu a tag regular-expressionna sua pergunta, mas a pergunta parece não especificar um motivo para fazer isso com expressões regulares. Se você está realmente procurando algo que use expressões regulares, stackoverflow.com/questions/17735289/… pode ser interessante. Essa pergunta era sobre o Notepad ++, mas a resposta não usa nada além de um pcre regex. (Disclaimer: Eu escrevi essa resposta.)
Jasper
Da próxima vez que você fizer uma pergunta, não há necessidade de escrever "Obrigado por isso. Ótima solução!" em todas as respostas. Isso é escrito mesmo quando você tenta criar um novo comentário em uma resposta.
pipe
Além disso, a maneira correta de demonstrar apreço aqui é aceitar a resposta que melhor funcionou para você e aprovar todas as respostas que julgar úteis ou úteis. As pessoas preferem ver isso a um comentário de agradecimento.
Camada B

Respostas:

19

Abordagem muito simples:

  1. Vá para a primeira linha que você deseja excluir.
  2. Grave uma macro: qa3ddjq
  3. Repita com um número alto: 1000 @ a

A etapa três repetirá a macro mil vezes ou até que um erro seja encontrado. Atingir o final do arquivo (portanto, nenhuma linha a ser excluída) produz um erro e a repetição da macro é cancelada.

Veja :help recording.

Ralf
fonte
2
Isso é incrível !!! Muito obrigado, que funcionou para mim: D
Max Copley
1
explicações: q(no modo de comando e no vim ou em outras versões alternativas recentes [neovim, etc], mas não no vi original) significa "iniciar a gravação e colocá-lo no buffer da 'próxima letra'". portanto: qasignifica "iniciar a gravação no buffer 'a'". Em seguida, todas as teclas digitadas após isso (até a próxima qno modo de comando) são gravadas (você pode até gravar: entrar no modo de edição, digitar algo, Escapar para o modo de comando, etc). Em seguida 12@a, repetiria quaisquer ações gravadas no buffer "a" 12 vezes.
Olivier Dulac
3
Além disso, se você não deseja executar algo como 1000@qno final, é possível criar uma macro recursiva:, qa3ddj@aq@aembora seja necessário qaqprimeiro fazer isso para garantir que ele "acomece vazio.
James
17

A solução mais fácil para mim seria:

:%norm j3dd

Isso é:

  • %: para cada linha
  • norm: execute as seguintes teclas como se estivesse no modo normal
  • j3dd: desça na linha e exclua 3 linhas

Então, da primeira linha, desça para a segunda e exclua as próximas 3 linhas. O segundo Text I want to keep.está agora na segunda linha. Desça uma linha, exclua 3. Enxágue e repita.


Nota: se você não quiser processar o arquivo inteiro, poderá substituí-lo %normpor, por exemplo, 5,$normpara processar da 5ª linha até o final do arquivo.

Marth
fonte
4
Alternativa muito boa! Funciona no vim (não vi). Eu nunca ouvi falar de "norma" antes! (e eu sou tipo de um totó vi [m])
Olivier Dulac
6

Você já tem ótimas soluções disponíveis. Aqui está outro:

:g/^/if line('.')%4!=1|:s/^/DELETE ME/|endif
:g/^DELETE ME/d

Primeiro, executamos uma ação em todas as linhas ( :gcorrespondendo ao ^(início da linha)) e, para cada número de linha, executamos o resultado de linenumber % 4. Se o resultado for desigual 1, adicionamos DELETE MEno início da linha, marcando as linhas a serem excluídas pelo próximo comando.

O próximo comando é um comando regular ( :g), que corresponde a todas as linhas que começam com DELETE MEe o fazem.

Observe que você não pode excluir imediatamente a linha usando o primeiro :gcomando, pois isso alteraria o cálculo do módulo resultante e, como tal, precisamos primeiro marcar as linhas e, em uma segunda etapa, excluí-la.

Christian Brabandt
fonte
4

Eu sei que este é o vicanal, mas para mim isso é um sedproblema.

sed -ne 'p;n;n;n' <file >newfile

Assim, você pode agrupá-lo em uma visolução:

:0
!Gsed -ne 'p;n;n;n'
dgc
fonte
1
+1 para uma solução sed.
Christian Brabandt
3

Uma alternativa (suponho que começamos na linha 1 e excluímos as linhas 2-4, 6-8 e assim por diante, conforme um exemplo de texto):

while line(".") < line("$")
    silent +1delete _ 3
endwhile

Se preferir fazer isso de maneira interativa, você pode usar o "registro de linha de comando". Ou seja, pressione

:+1del 3<CR> e depois 1000@:

Matt
fonte
1

uma alternativa: você deseja manter qualquer linha: 1, 4, etc. Você pode usar:

awk '!((FNR-1)%3)'  file > newfile
      # awk: when a condition is given without action:
      #        prints the lines for which the condition returns 0.
      # FNR designates the line number in the current file.
      # a%3 : takes the modulus of a and 3. ( 0%3=0, 1%3=1, 2%3=2, 3%3=0, 4%3=1, etc.) 
      # This will be 0 for 3, 6, etc. 
      # But we want it to be 0 (true) for 1, 4, etc : so we substract 1 to NR

# to see that it keeps those lines:
seq 1 20 | awk '!((NR-1)%3)'
1
4
7
10
13
16
19

Outra alternativa: se você conhece as linhas que deseja, corresponde a um padrão único:

# for exemple each line you want contains "some pattern":
fgrep "some pattern" file > newfile
# (or regular grep if you want "some pattern" to be interpreted as a regexp)
Olivier Dulac
fonte