Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/perl/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/.htaccess/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Regex Perl正则表达式按顺序查找包含关键字的字符串_Regex_Perl - Fatal编程技术网

Regex Perl正则表达式按顺序查找包含关键字的字符串

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

我正在学习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 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