Perl: как удалить конкретное слово или шаблон между двумя шаблонами - PullRequest
4 голосов
/ 25 апреля 2019

Я хочу удалить некоторые слова в двух шаблонах, используя perl

Ниже мой текст

..........

QWWK jhjh  kljdfh jklh jskdhf jkh PQXY
lhj ah jh sdlkjh PQXY jha slkdjh 
PQXY jh alkjh ljk
kjhaksj dkjhsd KWWQ
hahs dkj h PQXY
.........

Теперь я хочу удалить все PQXY слова, которые находятся только между двумя образцами. ^QWWK и KWWQ$

Я знаю, как заменить все это между двумя шаблонами следующей командой

perl -0777pe 's/^QWWK(?:(?!QWWK|KWWQ).)*KWWQ$/sometext/gms' filename

Также обратите внимание, что ^QWWK(?:(?!QWWK|KWWQ).)*KWWQ$ этот шаблон соответствует только тем, где между QWWK и KWWQ нет промежуточных.

Ответы [ 4 ]

3 голосов
/ 25 апреля 2019

Вы можете использовать оператор диапазона:

perl -pe 's/PQXY//g if /^QWWK/ .. /KWWQ$/'
2 голосов
/ 25 апреля 2019

Вот подход, который вы попробовали, с немного большим, необходимым для его работы

perl -0777 -wpe's{^(QWWK (?:(?!QWWK|KWWQ).)*? KWWQ)$}{ $1 =~ s/PQXY//gr }egmsx' file

Модификатор /e позволяет ему оценивать сторону замены как код,и мы запускаем регулярное выражение там.

В этом регулярном выражении модификатор /r заставляет его возвращать измененную строку (а не изменять оригинал, что позволяет нам запускать ее на $1, который доступен только для чтения).

Требование, чтобы блок текста ^QWWK -to- KWWQ$ не содержал ни одной из этих фраз, удовлетворялось приведенному выше коду, но некоторые комментарии могут быть полезны.

Мы не нужен не жадный .*?, поскольку .* (после негативного взгляда) фактически останавливается на KWWQ$.Но это сложно определить, и .* просто может поднять все до самого последнего KWWQ, включая все другие возможные блоки и любой текст между ними.

В целом я просто нахожу .*? безопаснее и проще, особенно если учесть, что - это , что нужно.

QWWK должен начинать строку (он задается с ^ в вопросе) быть маркером для блока.Если внутри блока обнаружен дополнительный QWWK, то весь блок не совпадает.Но если эта «лишняя» QWWK внутри окажется в начале строки, тогда

  • то, что было бы блоком, не совпадает, так как есть QWWK внутри

  • блок фактически соответствует, начиная с , что QWWK

Я использую /x вышечтобы иметь возможность разметить шаблон для удобства чтения.

1 голос
/ 25 апреля 2019

Если я правильно понимаю ваш вопрос, это может быть яснее с другими инструментами, чем регулярные выражения.Следующие слова сводят все пробелы между словами в один пробел.

Ввод qwwk.txt (с добавлением одной строки)

..........

QWWK jhjh  kljdfh jklh jskdhf jkh PQXY
lhj ah jh sdlkjh PQXY jha slkdjh
PQXY jh alkjh ljk
kjhaksj dkjhsd KWWQ
hahs dkj h PQXY
.........

KWWQ in mid line doesn't trigger: QWWK a PQXY b KWWQ c QWWK d PQXY e KWWQ

Команда perl qwwk.pl qwwk.txt

Выход

..........

QWWK jhjh kljdfh jklh jskdhf jkh
lhj ah jh sdlkjh jha slkdjh
jh alkjh ljk
kjhaksj dkjhsd KWWQ
hahs dkj h PQXY
.........

KWWQ in mid line doesn't trigger: QWWK a PQXY b KWWQ c QWWK d PQXY e KWWQ

Программа qwwk.pl

use strict; use warnings;
while(<>) {             # for each line
    my @out;
    my @words=split;    # get its words

    for my $i (0..$#words) {
        my $w=$words[$i];
        my $active = ($i==0 && $w eq q(QWWK)) .. ($i==$#words && $w eq q(KWWQ));
            # Keep track of where we are.  See notes below.
        push @out, $w unless $active and ($w eq q(PQXY));
            # Save words we want to keep
    } #foreach word

    print join(q( ), @out), qq(\n);     # Print the words we saved
} #foreach line

Ключ в том, чтоОператор триггера (..) в назначении $active= FOO .. BAR сохраняет свое состояние независимо от того, что происходит вокруг него.Это будет истинно от QWWK в начале строки (($i==0 && $w eq q(QWWK))) до KWWQ в конце строки (($i==$#words && $w eq q(KWWQ))), независимо от того, сколько строк вмешивается.

Как однострочный

perl -Mstrict -Mwarnings -ne 'my @out; my @words=split; for my $i (0..$#words) { my $w=$words[$i]; my $active = ($i==0 && $w eq q(QWWK)) .. ($i==$#words && $w eq q(KWWQ)); push @out, $w unless $active and ($w eq q(PQXY)); } print join(q( ), @out), qq(\n);' qwwk.txt

Разница здесь в том, что -n обеспечивает цикл while(<>){}, поэтому он не включен в скрипт -e.(Плюс, теперь вы знаете, почему я использовал q() и qq() в автономной программе;).)

1 голос
/ 25 апреля 2019

Обновление: Чтобы заменить PQXY, только если QWWK или KWWQ НЕ присутствуют между ^ QWWK и KWWQ $, попробуйте:

perl -pe 'if (/^QWWK/ .. /KWWQ$/) {s/PQXY//g if ! /.+QWWK/ && !/KWWQ.+/}' filename

Я уверен, что это можно почистить / сыграть в гольф, однако я думаю, что это даст вам то, о чем вы просите.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...