为什么运行相同的正则表达式两次产生不同的结果?

时间:2012-08-14 22:38:06

标签: regex perl

在尝试回答this问题时,我遇到了一些来自Perl的正则表达式引擎的奇怪行为。我有一个包含2个数量的字符串,我正在尝试与正则表达式匹配。正则表达式匹配字符串“units / ml”之前的任何8个字符。我想抓住两个单位。

此脚本仅打印匹配的第二个:

use warnings;
use strict;
my $line = 'some data 100,000 units/ml data 20,000 units/ml data';
my @array;
if ($line =~ m/.{8}units\/ml/g) {
    @array = $line =~ m/.{8}units\/ml/g;
    print join(' ', @array) . "\n";
}

其输出:

 20,000 units/ml

如果我两次运行第6行,那么分配给@array的行:

use warnings;
use strict;
my $line = 'some data 100,000 units/ml data 20,000 units/ml data';
my @array;
if ($line =~ m/.{8}units\/ml/g) {
    @array = $line =~ m/.{8}units\/ml/g;
    # Let's run that again, for good measure...
    @array = $line =~ m/.{8}units\/ml/g;
    print join(' ', @array) . "\n";
}

其输出:

100,000 units/ml  20,000 units/ml

为什么这两个脚本产生不同的结果?

3 个答案:

答案 0 :(得分:3)

这是因为你的if中的/ g修饰符。由于if在标量上下文中评估=〜,因此它只获得匹配的第一个项目。然后,在if块中,@ array指定从中断处继续搜索。 (这对于解析非常有用。)

当你运行额外的匹配时,你已经完成了匹配字符串中的所有内容,所以你从列表上下文中重新开始,然后你得到了所有内容。

如果删除if中的g标志,那么事情就会按预期工作。

答案 1 :(得分:1)

在这种情况下,选项是评估if语句中的数组赋值:

use Modern::Perl;

my $line = 'some data 100,000 units/ml data 20,000 units/ml data';
my @array;
if ( @array = $line =~ m/.{8}units\/ml/g ) {
    print join( ' ', @array ) . "\n";
}

输出:

100,000 units/ml  20,000 units/ml

如果没有匹配,可以采取适当的行动。

答案 2 :(得分:0)

问题出在这里

if ($line =~ m/.{8}units\/ml/g) { ... }

标量上下文中的全局匹配将匹配模式的 next 出现并设置标记以指示下一个全局匹配应从何处开始

之后只剩下20,000 units/ml个匹配模式,因此只匹配一次

要收集字符串后跟units/ml的所有数字或逗号,您应该写下这样的内容

use strict;
use warnings;

my $line = 'some data 100,000 units/ml data 20,000 units/ml data';

my @array = $line =~ m|([0-9,]+)\s*units/ml|g;

print "$_\n" for @array;

<强>输出

100,000
20,000