Regex Perl正则表达式按顺序查找包含关键字的字符串
我正在学习Perl。我想在文本中查找此顺序中出现的所有3个关键字:Regex Perl正则表达式按顺序查找包含关键字的字符串,regex,perl,Regex,Perl,我正在学习Perl。我想在文本中查找此顺序中出现的所有3个关键字:关键字1、关键字2和关键字3关键字1和关键字3是可选的。关键字之间最多可以有6个单词。以下是Perl中的代码: #!/usr/bin/perl $reg="(keyword1)*\W*(?:\w+\W+){0,6}?(keyword2)\W*(?:\w+\W+){0,6}?(keyword3)*"; $content="some words before keyword1 optional word here then keywo
关键字1
、关键字2
和关键字3
<代码>关键字1和关键字3
是可选的。关键字之间最多可以有6个单词。以下是Perl中的代码:
#!/usr/bin/perl
$reg="(keyword1)*\W*(?:\w+\W+){0,6}?(keyword2)\W*(?:\w+\W+){0,6}?(keyword3)*";
$content="some words before keyword1 optional word here then keyword2 again optional words then keyword3 others words after.";
while ($content=~m/$reg/g) {
print "$&\n";
}
我只想在这里提取子字符串关键字1可选单词,然后再提取关键字2可选单词,然后再提取关键字3
,但是我得到了关键字2
。谢谢。首先,“\w”
生成字符串w
,“\w”
生成字符串w
$ perl -wE'say "\w\W"'
Unrecognized escape \w passed through at -e line 1.
Unrecognized escape \W passed through at -e line 1.
wW
您需要避开反斜杠(“\\W”
)或使用qr/
(qr/\W/
)
我很确定这种模式还有其他问题。我要从头开始 假设
k1
和k3
都是独立可选的,您需要:
qr/
(?: \b k1 \W+
(?: \w+ \W+ ){0,6}?
)?
\b k2 \b
(?:
(?: \W+ \w+ ){0,6}?
\W+ k3 \b
)?
/x
单词边界(\b
)的存在是为了确保我们不匹配abck2def
或abck1 k2 k3def
上述方法效率低下 以以下正则表达式模式为例:
(?: x y )? x z
它可以匹配以下字符串:
xyxz
xz
请注意,两者都是以x
开头的?这意味着更好的模式(即执行较少回溯的模式)将是
在上面的回答中,有几个反模式的例子。所以让我们重构
qr/
\b
(?: k1 \W+ (?: \w+ \W+ ){0,6}? \b )?
k2 \b
(?: \W+ (?: \w+ \W+ ){0,6}? k3 \b )?
/x
现在我们有了一些有效的方法
在上面的模式中,请注意第二个
\b
是冗余的。所以,让我们摆脱它
如果我们在末尾添加一个\b
,那么第三个和第四个\b
将变得多余
应用这些简化后,我们得到:
qr/
\b
(?: k1 \W+ (?: \w+ \W+ ){0,6}? )?
k2
(?: \W+ (?: \w+ \W+ ){0,6}? k3 )?
\b
/x
qr/
\b
(?: k1 \W+ (?: (?! (?: k1 | k2 ) \b ) \w+ \W+ ){0,6} )?
k2
(?: \W+ (?: (?! (?: k2 | k3 ) \b ) \w+ \W+ ){0,6} k3 )?
\b
/x
就我个人而言,我非常不喜欢非贪婪修饰符,因为它不是一种优化。此外,其中两个的使用通常是一个巨大的危险信号,表明模式中存在错误。例如,模式可以匹配
k1 k1 k2
,但这可能并不理想
为了消除它们,我们需要确保第一个\w+
与k1
或k2
不匹配。这可以通过更换
\b \w+ \b
与
同样,我们将常见前缀分解为:
\b (?! (?: k2 | k3 ) \b ) \w+ \b
同样,我们需要确保第二个\w+
与k2
或k3
不匹配
通过这些更改,我们可以:
qr/
\b
(?: k1 \W+ (?: \w+ \W+ ){0,6}? )?
k2
(?: \W+ (?: \w+ \W+ ){0,6}? k3 )?
\b
/x
qr/
\b
(?: k1 \W+ (?: (?! (?: k1 | k2 ) \b ) \w+ \W+ ){0,6} )?
k2
(?: \W+ (?: (?! (?: k2 | k3 ) \b ) \w+ \W+ ){0,6} k3 )?
\b
/x
复杂?对更好的解决方案可以从将流分解为单词和非单词标记开始。这样做的好处是我们不必再担心边界问题
my @tokens = split(/(\W+)/, $content, -1);
然后,检查阵列的模式。由于正则表达式引擎在这方面特别擅长,我们可以如下利用它:
my $tokens =
join '',
map {
($_ % 2) ? "W"
: $words[$_] eq "k1" ? 1
: $words[$_] eq "k2" ? 2
: $words[$_] eq "k3" ? 3
: "w" # Non-key word
}
0..$#tokens;
while ($tokens =~ /(?: 1 W (?: w W ){0,6} )? 2 (?: W (?: w W ){0,6} 3 )?/xg) {
say join('', @tokens[ $-[0] .. $+[0] - 1 ]);
}
考虑到@tokens
始终采用word、non word、word、non word等形式,我们还可以使用以下内容:
my $words =
join '',
map {
($_ % 2) ? "" # We just want to look at the words
: $words[$_] eq "k1" ? 1
: $words[$_] eq "k2" ? 2
: $words[$_] eq "k3" ? 3
: "w" # Non-key word
}
0..$#tokens;
while ($words =~ /(?: 1 w{0,6} )? 2 (?: w{0,6} 3 )?/xg) {
say join('', @tokens[ $-[0] * 2 .. ( $+[0] - 1 ) * 2 ]);
}
首先,“\w”
生成字符串w
,“\w”
生成字符串w
$ perl -wE'say "\w\W"'
Unrecognized escape \w passed through at -e line 1.
Unrecognized escape \W passed through at -e line 1.
wW
您需要避开反斜杠(“\\W”
)或使用qr/
(qr/\W/
)
我很确定这种模式还有其他问题。我要从头开始 假设
k1
和k3
都是独立可选的,您需要:
qr/
(?: \b k1 \W+
(?: \w+ \W+ ){0,6}?
)?
\b k2 \b
(?:
(?: \W+ \w+ ){0,6}?
\W+ k3 \b
)?
/x
单词边界(\b
)的存在是为了确保我们不匹配abck2def
或abck1 k2 k3def
上述方法效率低下 以以下正则表达式模式为例:
(?: x y )? x z
它可以匹配以下字符串:
xyxz
xz
请注意,两者都是以x
开头的?这意味着更好的模式(即执行较少回溯的模式)将是
在上面的回答中,有几个反模式的例子。所以让我们重构
qr/
\b
(?: k1 \W+ (?: \w+ \W+ ){0,6}? \b )?
k2 \b
(?: \W+ (?: \w+ \W+ ){0,6}? k3 \b )?
/x
现在我们有了一些有效的方法
在上面的模式中,请注意第二个
\b
是冗余的。所以,让我们摆脱它
如果我们在末尾添加一个\b
,那么第三个和第四个\b
将变得多余
应用这些简化后,我们得到:
qr/
\b
(?: k1 \W+ (?: \w+ \W+ ){0,6}? )?
k2
(?: \W+ (?: \w+ \W+ ){0,6}? k3 )?
\b
/x
qr/
\b
(?: k1 \W+ (?: (?! (?: k1 | k2 ) \b ) \w+ \W+ ){0,6} )?
k2
(?: \W+ (?: (?! (?: k2 | k3 ) \b ) \w+ \W+ ){0,6} k3 )?
\b
/x
就我个人而言,我非常不喜欢非贪婪修饰符,因为它不是一种优化。此外,其中两个的使用通常是一个巨大的危险信号,表明模式中存在错误。例如,模式可以匹配
k1 k1 k2
,但这可能并不理想
为了消除它们,我们需要确保第一个\w+
与k1
或k2
不匹配。这可以通过更换
\b \w+ \b
与
同样,我们将常见前缀分解为:
\b (?! (?: k2 | k3 ) \b ) \w+ \b
同样,我们需要确保第二个\w+
与k2
或k3
不匹配
通过这些更改,我们可以:
qr/
\b
(?: k1 \W+ (?: \w+ \W+ ){0,6}? )?
k2
(?: \W+ (?: \w+ \W+ ){0,6}? k3 )?
\b
/x
qr/
\b
(?: k1 \W+ (?: (?! (?: k1 | k2 ) \b ) \w+ \W+ ){0,6} )?
k2
(?: \W+ (?: (?! (?: k2 | k3 ) \b ) \w+ \W+ ){0,6} k3 )?
\b
/x
复杂?对更好的解决方案可以从将流分解为单词和非单词标记开始。这样做的好处是我们不必再担心边界问题
my @tokens = split(/(\W+)/, $content, -1);
然后,检查阵列的模式。由于正则表达式引擎在这方面特别擅长,我们可以如下利用它:
my $tokens =
join '',
map {
($_ % 2) ? "W"
: $words[$_] eq "k1" ? 1
: $words[$_] eq "k2" ? 2
: $words[$_] eq "k3" ? 3
: "w" # Non-key word
}
0..$#tokens;
while ($tokens =~ /(?: 1 W (?: w W ){0,6} )? 2 (?: W (?: w W ){0,6} 3 )?/xg) {
say join('', @tokens[ $-[0] .. $+[0] - 1 ]);
}
考虑到@tokens
始终采用word、non word、word、non word等形式,我们还可以使用以下内容:
my $words =
join '',
map {
($_ % 2) ? "" # We just want to look at the words
: $words[$_] eq "k1" ? 1
: $words[$_] eq "k2" ? 2
: $words[$_] eq "k3" ? 3
: "w" # Non-key word
}
0..$#tokens;
while ($words =~ /(?: 1 w{0,6} )? 2 (?: w{0,6} 3 )?/xg) {
say join('', @tokens[ $-[0] * 2 .. ( $+[0] - 1 ) * 2 ]);
}
你的规格还很不清楚。您是否有实际的用例,或者这只是一个随机练习?始终使用
use strict;使用警告qw(全部)代码>!它应该捕获一个问题:\w
和\w
在双引号字符串文本中。转义斜杠或切换到使用qr/
qr/\b(?:k1\W+(?:\W+\W+{0,6}?)?k2(?:\W+(?:\W+\W+{0,6}?k3)\b/x
@ikegami这台机器非常好用!!!。非常感谢。@melpomene,这是一个练习。谢谢你的评论。你的规格还不清楚。您是否有实际的用例,或者这只是一个随机练习?始终使用use strict;使用警告qw