Ferramenta de linha de comando para facilitar a pesquisa de regex de múltiplas linhas e substituir

3

Eu uso expressões regulares do PCRE para procurar e substituir com muita frequência quando trabalho com um editor de texto e fiquei bastante infeliz depois que descobri que em poderosas ferramentas de linha de comando do Unix como perl , awk ou sed é É bastante complicado usar um pouco de regex multilinha avançada e requer várias sintaxes difíceis de lembrar para várias situações.

Existe uma ferramenta de linha de comando para Linux na qual procurar e substituir (para todas as ocorrências em todo o arquivo) usando um regex de múltiplas linhas mais complexo é tão simples quanto:

magicregextool 's/.* > (.*) joined the channel\.\n(((?!.*  (was kicked from channel\.|was banned from channel\.)\n).*\n)+?.* disconnected)//' file.txt

i.e. o regex para corresponder é o mesmo que eu colocaria no campo search for em um editor de texto, a string de substituição pode manipular multiline regex também e não há necessidade de nenhuma sintaxe complicada?

EDITAR:

Por solicitação, estou anexando uma entrada na qual eu usei o exemplo de regex acima e explicando o que realmente quero fazer.

Uma entrada como esta:

2016-05-16 06:17:00 > foobar joined the channel.
2016-05-16 06:17:13 <foobar> hi
2016-05-16 06:18:30 > foobar was kicked from channel.
2016-05-16 06:18:30 > foobar disconnected
2016-05-16 06:20:13 > user joined the channel.
2016-05-16 06:20:38 <user> bye
2016-05-16 06:21:57 > user disconnected

deve produzir esta saída:

2016-05-16 06:17:00 > foobar joined the channel.
2016-05-16 06:17:13 <foobar> hi
2016-05-16 06:18:30 > foobar was kicked from channel.
2016-05-16 06:18:30 > foobar disconnected
2016-05-16 06:20:38 <user> bye
2016-05-16 06:21:57 > user disconnected

A expressão regular corresponde a qualquer linha que contenha [username] joined the channel e procure uma linha abaixo dela que contenha [username] disconnected a menos que haja [username] was kicked from channel. ou [username] was banned from channel. entre essas duas linhas.

A string de substituição substitui o padrão correspondente por todas as linhas que seguem a linha com [username] joined the channel , excluindo efetivamente a linha 2016-05-16 06:20:13 > user joined the channel. da entrada acima.

O mais provável é que não faça sentido para você, mas este é apenas um exemplo de regex semelhante ao que eu lidei recentemente. Por favor, tenha em mente que eu não estou procurando uma solução para este problema específico ou problemas semelhantes com as ferramentas do Unix que listei acima. Estou procurando uma ferramenta de linha de comando que possa usar "search for" não modificada e strings de substituição que eu uso em um editor de texto (Geany, em particular, mas que realmente não deveria importar) sem uma sintaxe complicada ou que requer alguma lógica de programação adicional lidar com as strings de busca e substituição de múltiplas linhas.

    
por user2044638 15.05.2016 / 21:08

1 resposta

3

Não sei por que o Perl não é aceitável aqui. Nas entradas que você forneceu, esta linha fornece a saída que você pediu:

perl -0777p -e 's/.* > (.*) joined the channel\.\n(((?!.*  (was kicked from channel\.|was banned from channel\.)\n).*\n)+?.* disconnected)//mg' irc.txt

O argumento -e é exatamente o primeiro argumento para o seu magicregextool , exceto que eu adicionei o modificador /mg regex. Isso pode não ser "não modificado", mas também não parece irracional. Se você não quiser digitar a linha inteira, que tal esse script como magicregextool :

#!/usr/bin/perl -0777p
BEGIN { $::arg = shift @ARGV; }
eval $arg;

Ou até mesmo:

#!/bin/sh
perl -0777pe $*

Depois, basta digitar:

magicregextool 's/.* > (.*) joined the channel\.\n(((?!.*  (was kicked from channel\.|was banned from channel\.)\n).*\n)+?.* disconnected)//mg' irc.txt

Qual é o mesmo que a sua amostra (mais uma vez além de adicionar o modificador /mg ).

Um benefício adicional para isso é que, se você estiver executando várias operações de pesquisa / substituição relacionadas em cada arquivo, poderá reuni-las no mesmo script:

#!/usr/bin/perl -0777p
s/.* > (.*) joined the channel\.\n(((?!.*  (was kicked from channel\.|was banned from channel\.)\n).*\n)+?.* disconnected)//mg;
s/(some other\n)matched text//mg;
    
por 20.05.2016 / 09:02