Perl Regex Digit - PullRequest
       50

Perl Regex Digit

1 голос
/ 02 января 2012

У меня есть вопрос / проблема относительно моего регулярного выражения.Раздел кода ниже:

use strict;

my @list = ("1", "2", "123");

&chk(@list);

sub chk {
    my @num = split (" ", "@_");
    foreach my $chk (@num) {
        chomp $chk;
        if ($chk =~ m/\d{1,2}?/) {
            print "$chk\n";
        }
    }
}

\d{4} ничего не печатает.\d{3} будет печатать только 123.Но если я изменю на \d{1,2}?, он напечатает все.Я думал, что согласно всем источникам, которые я читал до сих пор, {1,2} означает: одну цифру, но не более двух.Так что он должен был печатать только 1 и 2, правильно?Что мне нужно, чтобы извлечь элементы, содержащие ТОЛЬКО одну или две цифры?Спасибо за любую помощь.

Ответы [ 6 ]

5 голосов
/ 02 января 2012

\ d {1,2} успешно выполняется, если он находит 1 или 2 цифры в любом месте указанной строки Дополнительное содержимое строки не приводит к сбою сопоставления. Если вы хотите сопоставить только когда строка содержит ровно 1 или 2 цифры, сделайте это: ^\d{1,2}$

1 голос
/ 02 января 2012

Кажется, он работает отлично!

Вот подсказка: используйте переменные Perl $`, $& и $'.Эти переменные являются специальными переменными регулярного выражения, которые показывают часть строки перед соответствием, что было сопоставлено, и строку после сопоставления.

Вот пример программы:

#! /usr/bin/env perl
use strict;
use warnings;
use feature qw(say);
use Scalar::Util;

my @list = ("1", "2", "123");

foreach my $string (@list) {
    if ($string =~ /\d{1,2}?/) {
        say qq(We have a match for "string"!);
        say qq("$`"  "$&"  "$'");
    }
    else {
        say "No match makes David Sad";
    }
}

Выходные данныебудет:

We have a match for "1"!
""  "1"  ""
We have a match for "2"!
""  "2"  ""
We have a match for "123"!
""  "1"  "23"

То, что это делает, делит строку на три секции: секцию строки до совпадения с регулярным выражением, секцию строки, которая соответствует регулярному выражению, и секциюстрока после совпадения с регулярным выражением.

В каждом случае не было предварительного совпадения , поскольку регулярное выражение совпадает с начала строки.Мы также видим, что \d{1,2}? соответствует одной цифре в каждом случае, даже если 123 может соответствовать двум цифрам.Зачем?Потому что вопросительный знак в конце спецификатора соответствия указывает регулярному выражению не быть жадным.В этом случае мы сообщаем регулярному выражению, что оно соответствует одному или двум символам.Хорошо, это соответствует одному.Удалите знак вопроса, и последняя строка выглядела бы так:

We have a match for "123"!
""  "12"  "3"

Если вы хотите сопоставить одну или две цифры, но не три или более цифр, вам нужно будет указать детальвашей строки до и после одной или двух цифр.Примерно так:

/\D\d{1,2}\D/

Это будет соответствовать вашей строке foo12bar, но не foo123bar.Но что, если строка 12?В этом случае мы хотим сказать, что либо у нас есть начало строки, либо не цифра перед совпадением с одним или двумя символами, и у нас либо не цифра, либо конец строки в конце нашегосовпадение из одного или двух символов:

/(\D|^)\d{1,2}(/D|$)/

Краткое объяснение:

  • (\D|^): не цифра или начало строки (якорь ^)
  • d{1,2}: одна или две цифры
  • (\D|$): не цифра или конец строки (якорь $)

сейчас, это будет соответствовать 12, но не 123, и это будет соответствовать foo12 и foo12bar, но не foo123 или foo123bar.

Просто ищет одну или две цифрычисло, мы можем просто указать якоря:

/^\d{1,2}$/;

Теперь это будет соответствовать 1, 12, но не foo12 или 123.

Главноеиспользовать переменные $`, $& и $', чтобы точно увидеть, с чем совпадает ваше регулярное выражение, а также что до и после совпадения.

1 голос
/ 02 января 2012

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

#!/usr/bin/env perl

use strict;
use warnings;

my @list = ( 1, 2, 123 );
print join "\n", grep /^\d{1,2}$/, @list;
0 голосов
/ 02 января 2012
#!/usr/bin/perl
use strict;
use warnings;
my @list = ("1", "2", "123");

&chk(@list);

sub chk {
my @num = split (" ", "@_");
foreach my $chk (@num) {
    chomp $chk;
    if ($chk =~ m/\d{1,2}/ && length($chk) <= 2) {
        print "$chk\n";
    }
}
}
0 голосов
/ 02 января 2012
#!/usr/bin/perl
use strict;

my @list = ("1", "2", "123");

&chk(\@list);

sub chk {

    foreach my $chk (@{$_[0]}) {
        print "$chk\n" if $chk =~ m/^\d{1,2}$/ ;        
    }
}
0 голосов
/ 02 января 2012

Нет, поскольку, хотя регулярное выражение соответствует только двум цифрам, $chk по-прежнему содержит 123. Если вы хотите распечатать только ту часть, которая соответствует, используйте

if ($chk =~ m/(\d{1,2})/) {
    print "$1\n";
}

Обратите внимание на круглые скобки и $ 1. Это заставляет его печатать только то, что в скобках.

Кроме того, этот код не имеет особого смысла:

sub chk {
    my @num = split (" ", "@_");

Поскольку @_ уже является массивом, нет смысла превращать его в строку, а затем разбивать его. Просто сделайте:

sub chk {
    foreach my $chk (@_) {

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

...