2

在尝试回答这个问题时,我遇到了 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

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

4

3 回答 3

3

这是因为 if 中的 /g 修饰符。由于 if 是在标量上下文中评估 =~ ,因此它只会获得匹配的第一个项目。然后,在您的 if 块内,@array 赋值从它停止的地方继续搜索。(这对解析很有用。)

当您运行额外匹配时,您已经完成匹配字符串中的所有内容,因此您在列表上下文中重新从头开始,然后您将获得所有内容。

如果你删除了 if 中的 g 标志,那么事情就会如你所愿。

于 2012-08-14T23:11:01.107 回答
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

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

于 2012-08-14T23:56:34.400 回答
0

问题就在这里

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

标量上下文中的全局匹配将匹配下一次出现的模式并设置一个标记来说明下一次全局匹配应该从哪里开始

之后只有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
于 2012-08-15T01:27:45.337 回答