Почему мое регулярное выражение терпит неудачу, когда число заканчивается на 0? - PullRequest
1 голос
/ 17 апреля 2010

Это действительно базовый вопрос регулярных выражений, но, поскольку я не могу понять, почему в некоторых обстоятельствах не удается найти совпадение, я решил опубликовать его, чтобы узнать, сможет ли кто-нибудь еще указать, что мне не хватает.

Я пытаюсь извлечь 2 набора цифр из строк вида:

12309123098_102938120938120938
1321312_103810312032123
123123123_10983094854905490
38293827_1293120938129308

Я использую следующий код для обработки каждой строки:

if($string && $string =~ /^(\d)+_(\d)+$/) {
    if(IsInteger($1) && IsInteger($2)) { print "success ('$1','$2')"; }
    else { print "fail"; }
}

Где функция IsInterger () выглядит следующим образом:

sub IsInteger {
    my $integer = shift;
    if($integer && $integer =~ /^\d+$/) { return 1; }
    return;
}

Эта функция, кажется, работает большую часть времени, но по какой-то причине не работает:

1287123437_1268098784380
1287123437_1267589971660

Любые идеи о том, почему они терпят неудачу, а другие преуспевают? Заранее спасибо за помощь!

Ответы [ 5 ]

3 голосов
/ 17 апреля 2010

Если сомневаетесь, проверьте, что на самом деле захватывает ваше регулярное выражение.

use strict;
use warnings;

my @data = (
    '1321312_103810312032123',
    '123123123_10983094854905490',
);

for my $s (@data){
    print "\$1=$1 \$2=$2\n" if $s =~ /^(\d)+_(\d)+$/;
    # Output:
    # $1=2 $2=3
    # $1=3 $2=0
}

Вы, вероятно, намеревались использовать второй из этих двух подходов.

(\d)+  # Repeat a regex group 1+ times,
       # capturing only the last instance.

(\d+)  # Capture 1+ digits.

Кроме того, и в вашем основном цикле, и в IsInteger (что кажется ненужным, учитывая начальное регулярное выражение в основном цикле), вы проверяете правду, а не что-то более конкретное, например defined или length. Ноль, например, является допустимым целым числом, но ложным.

3 голосов
/ 17 апреля 2010

Поскольку у вас есть 0 в конце второй строки, (\d)+ помещает только последнее совпадение в переменную $N, строка "0" эквивалентна false.

3 голосов
/ 17 апреля 2010

Это дополнение к ответам от Unicornaddict и ZyX: что вы пытаетесь сопоставить?

Если вы пытаетесь сопоставить последовательности слева и справа от '_', наркоман единорога верен, и ваше регулярное выражение должно быть ^(\d+)_(\d+)$. Кроме того, вы можете полностью избавиться от первого квалификатора и функции IsIntrger () - вы уже знаете, что это целое число - оно соответствует (\ d +)

if ($string =~ /^(\d+)_(\d+)$/) {
    print "success ('$1','$2')";
} else {
    print "fail\n";
}

Если вы пытаетесь сопоставить последнюю цифру в каждой и задаетесь вопросом, почему она не работает, это первая проверка IsInteger() (if($intger &&). В любом случае он избыточен (вы знаете, что это целое число) и не работает на 0, потому что, как отмечает ZyX, он оценивается как ложный.

То же самое относится и к:

if ($string =~ /^(\d)+_(\d)+$/) {
    print "success ('$1','$2')";
} else {
    print "fail\n";
}

Это выдаст success ('8','8') с учетом ввода 12309123098_102938120938120938

0 голосов
/ 20 апреля 2010

Многие люди прокомментировали ваше регулярное выражение, но проблема у вас была в вашем IsInteger (которая вам действительно не нужна для вашего примера).Вы проверили «истину», когда вы действительно хотите проверить определено :

sub IsInteger {
    my $integer = shift;
    if( defined $integer && $integer =~ /^\d+$/) { return 1; }
    return;
}

Вам не нужна большая часть инфраструктуры в этой подпрограмме:

sub IsInteger {
    defined $_[0] && $_[0] =~ /^\d+$/
}
0 голосов
/ 17 апреля 2010

Не следует включать + в группировку:

^(\d+)_(\d+)$ вместо ^(\d)+_(\d)+$

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...