perl:如何删除两个模式之间的特定单词或模式

问题描述 投票:4回答:4

我想用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单词只位于两个模式^QWWKKWWQ$之间

我知道如何通过以下命令替换两种模式之间的整个事物

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

另请注意,^QWWK(?:(?!QWWK|KWWQ).)*KWWQ$此模式仅匹配中间没有QWWK和KWWQ的模式。

regex perl multiline text-processing
4个回答
2
投票

这是你尝试过的方法,它需要更多的工作

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

/e modifier使得它将替换方评估为代码,并在那里运行正则表达式。

在该正则表达式中,/r修饰符使其返回已更改的字符串(而不是更改原始字符,允许我们在$1上运行它是只读的)。

^QWWK-to-KWWQ$文本块中不包含这些短语的要求得到上述代码的满足,但一些注释可能会有所帮助。

我们不需要非贪婪的.*?,因为.*(在负向前瞻之后)实际上停在KWWQ$。但这很难确定,而且.*有可能在最后一个KWWQ上啜饮,包括所有其他可能的块和它们之间的任何文本。

总而言之,我发现.*?更安全,更简单,特别是因为这是需要的。

QWWK必须开始一条线(在问题中用^给出)作为一个区块的标记。如果在块内找到额外的QWWK,则整个块不匹配。但是,如果内部的“额外”QWWK碰巧在一条线的开头那么

  • 什么是块不匹配,因为里面有QWWK
  • 实际上,一个区块与QWWK开始匹配

我使用上面的/x,以便能够将模式空间化以便于阅读。


3
投票

您可以使用范围运算符:

perl -pe 's/PQXY//g if /^QWWK/ .. /KWWQ$/'

1
投票

更新:仅当^ QWWK和KWWQ之间不存在QWWK或KWWQ时替换PQXY $尝试:

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

我相信它可以清理/打高尔夫球,但我认为它会给你你所要求的。


1
投票

如果我正确理解你的问题,除了正则表达式之外的其他工具可能会更清楚。以下操作会将单词之间的任何空格折叠为单个空格。

输入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();)。)

© www.soinside.com 2019 - 2024. All rights reserved.