1

假设我有以下字符串

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

出于某种原因,我得到了最后一个两次。

4

6 回答 6

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值(一次一个)。它将执行此操作,直到与您的模式匹配的所有“令牌”都被迭代。我喜欢这个解决方案,因为它简洁且不需要您创建辅助数组。这也是一个比在一个正则表达式中使用三个提取更普遍的答案。

于 2013-05-15T18:53:25.780 回答
1

而不是对抗正则表达式,使用splitand looks_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";
        }
    }    
}
于 2013-05-15T18:29:22.017 回答
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";
}
于 2013-05-15T18:29:30.503 回答
1

您有两组括号,因此返回两个值。两个集合都围绕正则表达式的同一部分,因此两个值将相同。


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

分两步进行,首先提取,非常简单:

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";
于 2013-05-15T18:29:33.520 回答
1

这里有几个问题:

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

2)为什么有两组括号?正如所写,第二对是多余的。

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

于 2013-05-15T18:33:40.520 回答
0

仅使用正则表达式

这将需要 3 个由空格分隔的数字块,每个数字将填充到其各自的组中。

(?:(?:^)([-]?[0-9]*?[.]?[0-9]*?)(?=\s))(?:(?:\s)([-]?[0-9]*?[.]?[0-9]*?)(?=\s))(?:(?:\s)([-]?[0-9]*?[.]?[0-9]*?)(?=$)) 在此处输入图像描述

例子

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
        )

)
于 2013-05-15T20:52:27.007 回答