perl:如何删除两个模式之间的特定单词或模式
perl: how to remove particular word or pattern in between two patterns
我想使用 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 -pe 's/PQXY//g if /^QWWK/ .. /KWWQ$/'
更新:
仅当 ^QWWK 和 KWWQ$ 之间不存在 QWWK 或 KWWQ 时才替换 PQXY 试试这个:
perl -pe 'if (/^QWWK/ .. /KWWQ$/) {s/PQXY//g if ! /.+QWWK/ && !/KWWQ.+/}' filename
我确定它可以清理/打高尔夫球,但我认为它会满足您的要求。
如果我正确理解你的问题,使用正则表达式以外的其他工具可能会更清楚。以下确实将单词之间的任何白色 space 折叠为单个 space.
输入 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()
了;)。)
这是您尝试过的方法,还需要稍微多一点才能发挥作用
perl -0777 -wpe's{^(QWWK (?:(?!QWWK|KWWQ).)*? KWWQ)$}{ =~ s/PQXY//gr }egmsx' file
/e
modifier 使其将替换端评估为代码,我们 运行 那里有一个正则表达式。
在该正则表达式中,/r
修饰符使其 return 更改后的字符串(而不是更改原始字符串,是什么让我们可以 运行 它在 </code> 上,这是只读)。</p>
<p>上面的代码满足 <code>^QWWK
-to-KWWQ$
文本块不包含任何这些短语的要求,但一些评论可能会有所帮助。
我们不需要 非贪婪 .*?
因为 .*
(在负前瞻之后)实际上停止在 KWWQ$
。但这很难确定,.*
有可能吞噬 所有 直到最后的 KWWQ
,包括所有其他可能的块和任何文本他们之间。
总而言之,我只是觉得 .*?
更安全、更简单,特别是 是 所需要的。
QWWK
必须开始一行(在问题中用 ^
给出)才能成为块的标记。如果在块内发现额外的 QWWK
则整个块不匹配。但是,如果里面的 "extra" QWWK
恰好在一行的开头,那么
块不匹配,因为里面有 QWWK
实际上匹配的是 that QWWK
我在上面使用 /x
以便能够 space 出模式以提高可读性。
我想使用 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 -pe 's/PQXY//g if /^QWWK/ .. /KWWQ$/'
更新: 仅当 ^QWWK 和 KWWQ$ 之间不存在 QWWK 或 KWWQ 时才替换 PQXY 试试这个:
perl -pe 'if (/^QWWK/ .. /KWWQ$/) {s/PQXY//g if ! /.+QWWK/ && !/KWWQ.+/}' filename
我确定它可以清理/打高尔夫球,但我认为它会满足您的要求。
如果我正确理解你的问题,使用正则表达式以外的其他工具可能会更清楚。以下确实将单词之间的任何白色 space 折叠为单个 space.
输入 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()
了;)。)
这是您尝试过的方法,还需要稍微多一点才能发挥作用
perl -0777 -wpe's{^(QWWK (?:(?!QWWK|KWWQ).)*? KWWQ)$}{ =~ s/PQXY//gr }egmsx' file
/e
modifier 使其将替换端评估为代码,我们 运行 那里有一个正则表达式。
在该正则表达式中,/r
修饰符使其 return 更改后的字符串(而不是更改原始字符串,是什么让我们可以 运行 它在 </code> 上,这是只读)。</p>
<p>上面的代码满足 <code>^QWWK
-to-KWWQ$
文本块不包含任何这些短语的要求,但一些评论可能会有所帮助。
我们不需要 非贪婪 .*?
因为 .*
(在负前瞻之后)实际上停止在 KWWQ$
。但这很难确定,.*
有可能吞噬 所有 直到最后的 KWWQ
,包括所有其他可能的块和任何文本他们之间。
总而言之,我只是觉得 .*?
更安全、更简单,特别是 是 所需要的。
QWWK
必须开始一行(在问题中用 ^
给出)才能成为块的标记。如果在块内发现额外的 QWWK
则整个块不匹配。但是,如果里面的 "extra" QWWK
恰好在一行的开头,那么
块不匹配,因为里面有
QWWK
实际上匹配的是 that
QWWK
我在上面使用 /x
以便能够 space 出模式以提高可读性。