【问题标题】:Perl regex to parse "1,2,3" into array of numbersPerl 正则表达式将“1,2,3”解析为数字数组
【发布时间】:2014-10-02 05:50:50
【问题描述】:

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

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 /,/ 来获取数组,但是要做到这一点的方法不止一种。我只是不太明白怎么做。救命!

【问题讨论】:

  • 我不会将此评论添加到所有三个答案中,而是将其添加到问题中。您可能不想想使用\d。而是使用[0-9]\d 匹配各种有趣的 Unicode 数字字符,例如“٣”和“”和“৩”和“୩”和“൩”。

标签: regex perl split


【解决方案1】:
/^(?:\d+,)*\d+\z/ or die;
my @numbers = /\d+/g;

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

【讨论】:

    【解决方案2】:

    只需要正则表达式来过滤掉非数字。 split 在这里更有用:

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

    正如所指出的,这会将空字符串视为空列表。这可能是也可能不是您希望它的工作方式。

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

    【讨论】:

    • 它将空字符串视为数字列表。这可能不是我们想要的。
    • 它可能是也可能不是,但无论哪种方式都没有明确的要求,这只是我们的猜测。尽管如此,我很确定我不希望 \z 在我的 grep 块中包含换行符。
    • 另外,还有更好的方法来防范空字符串。
    【解决方案3】:

    我建议将验证与解析分开:

    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";
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-07-31
      • 1970-01-01
      • 2023-03-04
      • 2011-03-16
      • 2020-08-08
      • 1970-01-01
      • 1970-01-01
      • 2014-10-28
      相关资源
      最近更新 更多