Exclua n linhas seguindo um padrão (e a linha correspondente ao padrão)

1

Como posso excluir uma linha contendo um padrão de correspondência e as seguintes n linhas usando uma ferramenta que suporta expressões regulares?

Em outras palavras, como escrever uma expressão regular que corresponda a uma linha contendo um padrão de correspondência e as seguintes n linhas, para que eu possa substituí-las por nada?

Por exemplo, se eu tiver um padrão de correspondência bbbb e quiser excluir também as 5 linhas que o seguem, para o arquivo de entrada:

aldjflajdkl
aaaabbbbaaaa
1l;adfjl
2aldfjl
3adlflkdas
4aldfjd
5aldfkld
6dlafjlkdas

A saída seria:

aldjflajdkl
6dlafjlkdas

Ele provavelmente simplifica coisas que, no meu caso específico, não podem ser que o padrão de correspondência ( bbbb ) esteja contido nas 5 linhas seguintes.

Já existe uma solução para o sed , mas ela depende apenas parcialmente em expressões regulares, e usa comandos de substituição personalizados que não são portáteis.

    
por Antonio 08.04.2015 / 14:52

2 respostas

2

Uma possível solução é:

.*<matching pattern>(.*\r?\n){<N+1>}

em que N é o número de linhas que desejo remover após a linha que contém o padrão.

Para o exemplo dado, isso se traduz em:

.*bbbb(.*\r?\n){6}

É assim que parece no grepWin:
Notaslaterais:

  • Naguia"A sequência de caracteres de pesquisa regex corresponde", também a linha 5aldfkld está marcada para ser correspondida; na verdade, uma barra de rolagem é visível à direita
  • (específico do grepWin) Devido a um pequeno bug, ao aplicar essa pesquisa nos arquivos, você verá a contagem de correspondências aumentando em 7 para cada correspondência! Provavelmente, isso ocorre porque o contador de correspondência conta quantas linhas são correspondidas e, nesse caso, o padrão cobre 7 linhas: a linha correspondente, as 5 linhas seguintes e a linha alcançada com o último feed de linha
  • (sed específico) Esse regex não funciona para sed , que não suporta totalmente regex e tem .

O seguinte explica como cheguei à solução.

Eu comecei em:

.*bbbb.*\n.*\n.*\n.*\n.*\n.*\n

que não funcionaria no meu sistema. Mas o seguinte funcionaria:

.*bbbb.*\r\n.*\r\n.*\r\n.*\r\n.*\r\n.*\r\n

Então, estou trabalhando em um sistema CRLF. No entanto, isso não parece muito bonito nem portátil.

Eu posso torná-lo um pouco mais portátil (e mais feio :-)) fazendo:

.*bbbb.*\r?\n.*\r?\n.*\r?\n.*\r?\n.*\r?\n.*\r?\n

(O retorno de carro se torna opcional). Ainda parece feio, mas posso coletar o termo repetitivo:

.*bbbb(.*\r?\n){6}

Este guia foi muito útil.

    
por 08.04.2015 / 15:19
1

Uma solução awk :

awk '/bbbb/ {i=5; next} {if (i>0) i--; else print}'

Quando detecta o padrão que você está procurando, define i (que é um contador de contagem regressiva) para 5, e pula o restante do processamento (isto é, pula para a próxima linha de entrada). Em particular, não imprime a linha. (Dizer /bbbb/ {i=5+1} para a primeira parte seria equivalente; escolha um com base na sua preferência de estilo.) Então, se o contador for positivo, diminua (subtraia 1) para contar as linhas que estão sendo excluídas (ignoradas) e não imprimem; caso contrário, imprima a linha.

    
por 09.04.2015 / 06:38