使用Perl指定匹配的正则表达式组的数量

时间:2013-05-15 18:19:46

标签: regex perl regex-group

假设我有以下字符串

my $val = "3.4 -22.352 4.0"

目标是自己提取每个十进制数字。每侧或其间可以有任意数量的空间。确保正好有3个数字,而且没有其他垃圾也很重要。我有这样的东西,但它不起作用:

my @parts = ($val =~ /((\s*[-+]?\d{1,3}\.\d{1,3}\s*)){3}/)

if (scalar(@parts) == 3) {
    print "Validated!\n";

    for my $i (@parts) {
        print "$i\n";
    }
}

由于某种原因,我得到了最后一次。

6 个答案:

答案 0 :(得分:1)

使用splitlooks_like_number

,而不是与正则表达式作斗争
use warnings;
use strict;
use Scalar::Util qw(looks_like_number);

my $val = "3.4 -22.352 4.0";
my @parts = split /\s+/, $val;
if (scalar(@parts) == 3) {
    my $ok = 0;
    for (@parts) {
        $ok++ if looks_like_number($_);
    }
    if ($ok == 3) {
        print "Validated!\n";
        for my $i (@parts) {
            print "$i\n";
        }
    }    
}

答案 1 :(得分:1)

每个捕获组只获得一个值,即使您在其上应用量词也是如此。如果您想要3个值,则必须重复捕获组3次。例如:

my $num = qr/[-+]?\d{1,3}\.\d{1,3}/;
my @nums = $val =~ /^\s*($num)\s+($num)\s+($num)\s*$/;

if(@nums){
    print "Valid, and no need to check the number of elements.\n";
}

答案 2 :(得分:1)

您有两组parens,因此返回两个值。两个集都围绕正则表达式的相同部分,因此两个值都是相同的。


验证和提取不一定可能同时进行。

分两步完成,先提取,非常简单:

my @nums = split ' ', $val;
die "Invalid\n" if @parts != 3;
for (@nums) {
   die "Invalid\n" if !/^[-+]?[0-9]{1,3}\.[0-9]{1,3}\z/;
}

您可以一步完成,但需要一些冗余:

my $num_pat = qr/[-+]?[0-9]{1,3}\.[0-9]{1,3}/;
my @nums = $val =~ /^($num_pat)\s+($num_pat)\s+($num_pat)\z/
   or die "Invalid\n";

答案 3 :(得分:1)

这里有几个问题:

1)如果你想要三个且只有三个数字,你应该在正则表达式中锚定行的开头(^)和结束($)。

2)为什么有两套括号?如上所述,第二对是多余的。

3)当你有一个正则表达式时,返回的值的数量通常由左括号计算(除非你使用?:或其他一些修饰符)。在此示例中,您有两个,因此它只返回两个值。由于冗余括号,每次都会得到两次相同的值。

答案 4 :(得分:1)

my $val = "3.4 -22.352 4.0";
my $length = $val =~ s/((^|\s)\S)/$1/g;
#determines the number of tokens

if ($length == 3)
{
     while($val=~/([-+]?[0-9]{1,3}\.[0-9]{1,3})/g)
     {
         print "$1\n";
     }
}

/g允许您遍历字符串并提取符合您的限制的值(一次一个)。它将执行此操作,直到所有与您的模式匹配的“标记”被迭代完毕。我喜欢这个解决方案,因为它简洁,不需要您创建辅助数组。在一个正则表达式中使用三个提取也是一个更普遍的答案。

答案 5 :(得分:0)

仅限正则表达式

这将需要3个以空格分隔的数字块,每个数字将被分别插入其各自的组中。

(?:(?:^)([-]?[0-9]*?[.]?[0-9]*?)(?=\s))(?:(?:\s)([-]?[0-9]*?[.]?[0-9]*?)(?=\s))(?:(?:\s)([-]?[0-9]*?[.]?[0-9]*?)(?=$)) enter image description here

实施例

PHP Code Example: 
<?php
$sourcestring="3.4 -22.352 4.0";
preg_match_all('/(?:(?:^)([-]?[0-9]*?[.]?[0-9]*?)(?=\s))(?:(?:\s)([-]?[0-9]*?[.]?[0-9]*?)(?=\s))(?:(?:\s)([-]?[0-9]*?[.]?[0-9]*?)(?=$))/i',$sourcestring,$matches);
echo "<pre>".print_r($matches,true);
?>

$matches Array:
(
    [0] => Array
        (
            [0] => 3.4 -22.352 4.0
        )

    [1] => Array
        (
            [0] => 3.4
        )

    [2] => Array
        (
            [0] => -22.352
        )

    [3] => Array
        (
            [0] => 4.0
        )

)