与/ g修饰符一起使用时,级联正则表达式不匹配

时间:2014-10-29 10:00:00

标签: regex perl

让我们考虑一下这个程序:

#!/usr/bin/env perl
use 5.014;
use strict;
use warnings;

my $file = <<END_FILE;
*   Action    : Lorem ipsum
*               Dolor oktam
*               Lorem lorem
*
*   Input     : var1
*               var2
*               var3
*
*   Output    : var4
*               var5
*               var6
END_FILE


$_ = $file;

my ($action, $input) = ('', '');

if (/action\s+:\s*((.|\r\n|\n)*?)(\r\n|\n).*\s*input/gi) {
    say "Action: $1";
}

# Not capture anything
if (/input\s+:\s*((.|\r\n|\n)*?)(\r\n|\n).*\s*output/gi) {
    say "Input: $1";
}

# But this time it works
if ($file =~ /input\s+:\s*((.|\r\n|\n)*?)(\r\n|\n).*\s*output/gi) {
    say "Input OK: $1";
}

# And $_ isn't different from $file
die "WTF!" unless $_ eq $file;

我想在&#34; Action&#34;,&#34;输入&#34;之后提取信息。和&#34;输出&#34;。当我尝试在输入&#34;输入&#34;之后获取信息时,会发生奇怪的事情。如果我使用$_,则正则表达式不会匹配任何内容,但即使$file

我使用$_ eq $file也可以使用

我的问题来自哪里?

我得到的输出是:

Action: Lorem ipsum
*               Dolor oktam
*               Lorem lorem
*
Input OK: var1
*               var2
*               var3
*

1 个答案:

答案 0 :(得分:6)

这是因为您正在使用/g,这将使下一场比赛尝试在最后一场比赛结束后找到匹配项。由于第一个匹配将使用input,因此第二个匹配将在input之后开始,因此永远不会找到另一个匹配的input

您可以删除/g来解决此问题。

perlop会告诉你:

  

/g修饰符指定全局模式匹配 - 即匹配   字符串中尽可能多的次数。它的表现取决于   上下文。在列表上下文中,它返回子字符串的列表   与正则表达式中的任何捕获括号匹配。如果   没有括号,它返回所有匹配的列表   字符串,好像整个模式周围都有圆括号。

     

在标量上下文中,m//g的每次执行都会找到下一个匹配项,然后返回   如果匹配则为true,如果没有进一步匹配则为false。该   可以使用pos()读取或设置最后一场比赛后的位置   功能;见pos。失败的匹配通常会重置搜索位置   到字符串的开头,但你可以通过添加来避免这种情况   / c修饰符(例如,m//gc)。也修改目标字符串   重置搜索位置