Как получить идеальное соответствие для регулярного выражения в Perl? - PullRequest
0 голосов
/ 11 октября 2011

Мне нужно сопоставить регулярное выражение, хранящееся в переменной:

#!/bin/env perl

use warnings;
use strict;
my $expr = qr/\s*(\w+(\[\d+\])?)\s+(\w+(\[\d+\])?)/sx;
$str = "abcd[3] xyzg[4:0]";
if ($str =~ m/$expr/) {
    print "\n%%%%%%%%% $`-----$&-----$'\n";
}
else {
    print "\n********* NOT MATCHED\n";
}

Но я получаю значение в $ & as

%%%%%%%%% -----abcd[3] xyzg-----[4:0]

Но ожидаемо, оно не должно входить в предложение if. То, что предназначено, является:

if $str = "abcd xyzg" => %%%%%%%%% -----abcd xyzg-----            (CORRECT)
if $str = "abcd[2] xyzg" => %%%%%%%%% -----abcd[2] xyzg-----      (CORRECT)
if $str = "abcd[2] xyzg[3] => %%%%%%%%% -----abcd[2] xyzg[3]----- (CORRECT)
if $str = "abcd[2:0] xyzg[3] => ********* NOT MATCHED             (CORRECT)
if $str = "abcd[2:0] xyzg[3:0] => ********* NOT MATCHED           (CORRECT)
if $str = "abcd[2] xyzg[3:0]" => ********* NOT MATCHED            (CORRECT/INTENDED)

, но вывод %%%%%%%%% -----abcd[2] xyzg-----[3:0] (WRONG) ИЛИ лучше сказать, что это не предназначено.В этом случае он должен / my_expectation перейти в блок else.Даже я не знаю, почему $ & берут часть строки ( abcd [2] xyzg ) и $ ' с [3: 0] ? КАК ?Он должен соответствовать полностью, а не части, как указано выше.Если это не так, то не следует переходить к предложению , если .

Может кто-нибудь помочь мне изменить мой шаблон $ expr, чтобы я мог получить то, что предполагалось?

Ответы [ 2 ]

4 голосов
/ 11 октября 2011

По умолчанию регулярные выражения Perl ищут только совпадающую подстроку данной строки.Для принудительного сравнения по всей строке необходимо указать, что регулярное выражение начинается в начале строки и заканчивается в конце, используя ^ и $:

my $expr = qr/^\s*(\w+(\[\d+\])?)\s+(\w+(\[\d+\])?)$/;

(такженет никакой причины иметь модификатор /x, поскольку ваше регулярное выражение не содержит буквального пробела или символов #, и нет причины для модификатора /s, так как вы не используете ..)

РЕДАКТИРОВАТЬ: Если вы не хотите, чтобы регулярное выражение совпадало со всей строкой, но вы хотите, чтобы оно отклоняло все, в чем за соответствующей частью следует что-то вроде «[0: 0]», самый простойможно было бы использовать lookahead:

my $expr = qr/^\s*(\w+(\[\d+\])?)\s+(\w+(\[\d+\]|(?=[^[\w])|$ ))/x;

Это будет соответствовать всему, что принимает следующую форму:

  • начало строки (что, по-видимому, подразумевается в вашем примере в комментариях)хотите)
  • ноль или более символов пробела
  • один или несколько символов слова
  • необязательно: [, одна или несколько цифр, ]
  • один или несколько пробельных символов
  • один или несколько символов слова
  • один из следующих пунктов в порядке убывания предпочтений:
      • [, одна или несколько цифр ]
      • пустая строка, за которой следует (но не включает!) Символ, который не является ни [, ни символом слова (Исключение символов словачтобы не дать обработчику регулярных выражений выполнить «a[0] bc[1:2]», только сопоставив «a[0] b».)
      • конец строки (после пробела$, чтобы не допустить слияния со следующим ) для формирования имени специальной переменной, что влечет за собой повторное введение опции /x.)

У вас есть еще неустановленные требования, которые необходимо удовлетворить?

1 голос
/ 11 октября 2011

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

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

Вот мой общий ответ, когда у вас возникают проблемы с проверкой регулярного выражения.Используйте инструмент регулярных выражений, например regex buddy one.

Так что я собираюсь дать конкретный ответ о том, что вы пропускаете здесь:
Давайте уменьшим этот пример:Ваш шаблон a(bc+d)?.Он будет соответствовать: abcd abccd и т. Д. Хотя он не будет совпадать с bcd и bzd в случае abzd, он будет совпадать как совпадающий только с a, поскольку вся группа bc+d является необязательной.,Точно так же он будет соответствовать abcbcd как a, отбрасывая всю необязательную группу, которая не может быть сопоставлена ​​(во втором b).

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

Вот что вы пробовали:
qr/\s*(\w+(\[\d+\])?)\s+(\w+(\[\d+\])?)/sx
Сначала s иx здесь не нужны модификаторы.
Во-вторых, это регулярное выражение может соответствовать:
Любой пробел или его отсутствие, за которым следует
слово, по крайней мере, с одним буквенным символом, за которым следует
, необязательно, сгруппированный квадратный скобкачисло с хотя бы одной цифрой (например, [0] или [9999]), за которым следует хотя бы один пробел, за которым следует
слово, состоящее не менее чем из одного буквенного символа, за которым следует
, необязательно, квадратный номер в скобках с хотя бы однимцифра.

Ясно, что когда вы просите, чтобы он совпадал с abcd[0] xyzg[0:4], двоеточие заканчивает шаблон \d+, но не удовлетворяет \], поэтому он возвращает всю группу, а затем счастливо находит группу необязательной.,Таким образом, не сопоставляя последнюю необязательную группу, ваш шаблон успешно соответствует.

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