我想用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的模式。
这是你尝试过的方法,它需要更多的工作
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
,以便能够将模式空间化以便于阅读。
您可以使用范围运算符:
perl -pe 's/PQXY//g if /^QWWK/ .. /KWWQ$/'
更新:仅当^ QWWK和KWWQ之间不存在QWWK或KWWQ时替换PQXY $尝试:
perl -pe 'if (/^QWWK/ .. /KWWQ$/) {s/PQXY//g if ! /.+QWWK/ && !/KWWQ.+/}' filename
我相信它可以清理/打高尔夫球,但我认为它会给你你所要求的。
如果我正确理解你的问题,除了正则表达式之外的其他工具可能会更清楚。以下操作会将单词之间的任何空格折叠为单个空格。
输入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()
;)。)