2014-10-02 29 views
-1

我希望Perl检查一个字符串是否包含完全由逗号分隔的数字列表,然后将其分割成数组。正则表达式/^(\d+)(?:,(\d+))*$/)做我想要的解析,但是当我在列表上下文中评估它时,我只能得到第一个和最后一个数字。我尝试/(?:^|,)(\d+)(?=,|$)/g以使修改器发挥作用以发出多个匹配,但是这不能完全检查语法,如以下示例所示。那么如何获得像第一个完全锚定的正则表达式来向()*发出多个匹配数组?Perl正则表达式来解析“1,2,3”到数组数组

foreach (@ARGV) { 
    #if (my @numbers = /^(\d+)(?:,(\d+))*$/) { 
    if (my @numbers = /(?:^|,)(\d+)(?=,|$)/g) { 
    print "$_ = (@numbers)\n"; 
    } else { 
    print "$_ isn't a number list!\n"; 
    } 
} 

把上面在一个叫numberlist.pl文件并运行它,你会得到这样的: -

bash$ perl numberlist.pl 1,2,3 ,1,2,3 1,2,3, a,2,3 1,b,3 1,2,c aa1,2,3zz 
1,2,3 = (1 2 3) 
,1,2,3 = (1 2 3) 
1,2,3, = (1 2 3) 
a,2,3 = (2 3) 
1,b,3 = (1 3) 
1,2,c = (1 2) 
aa1,2,3zz = (2) 

如果取消对第一if和评论第二,那么你会得到: -

1,2,3 = (1 3) 

因此(?:)内部的()的内容发出单个匹配,而不是匹配列表。

我知道我可以使用第一个正则表达式来检查语法,然后使用my @numbers = split /,/来获取数组,但还有更多的方法可以做到这一点。我只是不太明白如何。帮帮我!

+1

而不是将此评论添加到所有三个答案,我会添加它的问题。你可能**不要**想使用'\ d'。而是使用'[0-9]'。 '\ d'匹配各种有趣的Unicode数字字符,如“3”和“߃”和“3”以及“୩”和“3”。 – tobyink 2014-10-02 06:34:37

回答

0
/^(?:\d+,)*\d+\z/ or die; 
my @numbers = /\d+/g; 

my @numbers = split /,/; 
die if [email protected]; 
for (@numbers) { 
    die if !/^\d+\z/; 
} 
0

只需要正则表达式,用于过滤掉非数字。 split是比较有用的位置:

for (@ARGV) { 
    next unless $_; # Add this to skip processing of blank entries. 
    my @l = grep {/^\d+\z/} split /,/; 
    print "$_ = (@l)\n"; 
} 

正如指出的那样,这将把一个空字符串为空列表。这可能是也可能不是你想要它的工作方式。

如果您不介意输入字符串末尾有\n的可能性,请将该模式中的\z更改回$

+0

它将空字符串视为一个数字列表。这可能不是期望的。 – ikegami 2014-10-02 06:19:20

+0

它可能会也可能不会,但没有明确的要求,这只是我们的猜测。所有相同的,我很确定我不希望'\ z'在我的'grep'块中包含换行符。 – md4 2014-10-02 06:20:44

+0

此外,还有更好的方法来防止空字符串。 – md4 2014-10-02 06:22:14

0

我会建议从解析分离验证:

use strict; 
use warnings; 

local @ARGV = do { 
    no warnings 'qw'; 
    qw(1,2,3 ,1,2,3 1,2,3, a,2,3 1,b,3 1,2,c aa1,2,3zz); 
}; 

for (@ARGV) { 
    if (/^\d+(?:,\d+)*$/) { 
     my @numbers = split ','; 
     print "Numbers are @numbers\n"; 
    } else { 
     print "NaN = $_\n"; 
    } 
} 

输出:

Numbers are 1 2 3 
NaN = ,1,2,3 
NaN = 1,2,3, 
NaN = a,2,3 
NaN = 1,b,3 
NaN = 1,2,c 
NaN = aa1,2,3zz 

但是,如果你连接到连接它们,然后验证使用正前向断言和捕获外部像这样:

for (@ARGV) { 
    if (my @numbers = /\G(?=\d+(?:,\d+)*$)(\d+),?/g) { 
     print "Numbers are @numbers\n"; 
    } else { 
     print "NaN = $_\n"; 
    } 
}