2012-08-14 189 views
2

在试图对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 

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

回答

4

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

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

如果您在if中删除g标志,那么事情就像您期望的那样工作。

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 

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

+1

是的,这是非常接近我会怎么做。然而,你可以把我放入if语句中:'if(my @array = ...){@array valid valid here} but not here' – Tanktalus 2012-08-15 15:09:28

+0

@Tanktalus - 确实,你可以,而且这很好。 +1 – Kenosis 2012-08-15 16:05:01

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 
相关问题