2013-05-15 2 views
1

Допустим, у меня есть следующая строкаУкажите количество совпадающих регулярных выражений групп с помощью Perl

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

По какой-то причине я получаю последнее дважды.

ответ

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

Вместо того чтобы бороться регулярных выражений, используйте split и 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"; 
     } 
    }  
} 
+0

'расщепленные/\ S + /' удаляет конечные пробелы. 'split ''' также удаляет ведущие пробелы. Вероятно, лучший вариант. – ikegami

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

Там несколько вопросов здесь :

1) Если вам нужны три и только три числа, вы должны привязать начало (^) и конец ($) строки в регулярном выражении.

2) Почему существуют два набора круглых скобок? Как написано, вторая пара избыточна.

3) Когда у вас есть регулярное выражение, количество возвращаемых значений обычно подсчитывается левыми скобками (если вы не используете?: Или какой-либо другой модификатор). В этом примере у вас есть два, поэтому он возвращает только два значения. Из-за избыточных круглых скобок вы получаете одинаковые значения дважды.

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 позволяет перебрать значение строк и вытяжного, соответствующее ваши ограничения (по одному). Он будет делать это до тех пор, пока все «токены», соответствующие вашему шаблону, не будут повторяться. Мне нравится это решение, потому что оно кратким и не требует создания вспомогательного массива. Это также более общий ответ, чем использование трех выделений в регулярном выражении.

0

С Regex Только

Это потребует 3 ломтей чисел, разделенных пробела каждого номера будет popluated под соответствующую группу.

(?:(?:^)([-]?[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 
     ) 

) 
Смежные вопросы