Почему я не могу сопоставить подстроку, которая может появляться 0 или 1 раз, используя / (subpattern)? / - PullRequest
0 голосов
/ 03 марта 2011

Исходная строка выглядит следующим образом:

checksession ok:6178 avg:479 avgnet:480 MaxTime:18081 fail1:19

Последняя часть " fail1: 19 " может появляться 0 или 1 раз.И я попытался сопоставить число после " fail1: ", то есть 19, используя это:

($reg_suc, $reg_fail) = ($1, $2) if $line =~ /^checksession\s+ok:(\d+).*(fail1:(\d+))?/;

Это не работает.Переменная $ 2 пуста, даже если " fail1: 19 " существует.Если я удаляю «?», Он может совпадать, только если существует часть « fail1: 19 ».Переменная $ 2 будет « fail1: 19 ».Но если часть " fail1: 19 " не существует, $ 1 и $ 2 также не совпадают.Это неверно.

Как я могу переписать этот шаблон, чтобы правильно захватить число 2?Это означает, что при наличии части " fail1: 19 " будут записаны два числа, а когда она не выйдет, будет записана только цифра после " ok: ".

Ответы [ 4 ]

6 голосов
/ 03 марта 2011

Во-первых, число в поле fail оканчивается на $3, так как эти переменные заполняются в соответствии с открывающими скобками.Во-вторых, как показывает кодаддикт, конструкция .* в RE голодна, поэтому она съест даже часть fail....В-третьих, вы можете избежать нумерованных переменных, таких как:

my $line = "checksession ok:6178 avg:479 avgnet:480 MaxTime:18081 fail1:19";
if(my ($reg_suc, $reg_fail, $addend)
    = $line =~ /^checksession\s+ok:(\d+).*?(fail1:(\d+))?$/
) {
    warn "$reg_suc\n$reg_fail\n$addend\n";
}
2 голосов
/ 03 марта 2011

Попробуйте регулярное выражение:

^checksession\s+ok:(\d+).*?(fail1:(\d+))?$

Ideone Link

Изменения сделаны:

  • .* в середине было сделано не жадный и
  • $ (конечный якорь) был добавлен.

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

1 голос
/ 04 марта 2011

Я стараюсь избегать не жадного модификатора. Это часто кусает назад. Слава за предложение разделить, но я бы пошел дальше:

my %rec = split /\s+|:/, ( $line =~ /^checksession (.*)/ )[0];
print "$rec{ok} $rec{fail1}\n";
1 голос
/ 03 марта 2011

Я думаю, что это один из немногих случаев, когда разделение на самом деле более надежно, чем регулярное выражение:

$bar[0]="checksession ok:6178 avg:479 avgnet:480 MaxTime:18081 fail1:19";
$bar[1]="checksession ok:6178 avg:479 avgnet:480 MaxTime:18081";
for $line (@bar){
    (@fields) = split/ /,$line;
    $reg_suc = $fields[1];
    $reg_fail = $fields[5];
    print "$reg_suc $reg_fail\n";
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...