Какие символы я должен экранировать в предварительно скомпилированном регулярном выражении Perl?

Мне трудно определить, какие символы должны экранироваться при использовании конструкции Perl qr{}

Я пытаюсь создать многострочное предварительно скомпилированное регулярное выражение для текста, которое содержит множество обычно экранированных символов (#*.>:[]), а также содержит другое предварительно скомпилированное регулярное выражение. Кроме того, мне нужно максимально строго соответствовать для целей тестирования.

my $output = q{# using defaults found in .config
*
*
Options:
  1. opt1
> 2. opt2
choice[1-2?]: };

my $sc = qr{(>|\s)}smx;
my $re = qr{# using defaults found in .config
*
*
Options:
$sc 1. opt1
$sc 2. opt2
choice[1-2?]: }mx;

if ( $output =~ $re ) {
  print "OK!\n";
}
else {
  print "D'oh!\n";
}

Ошибка:

Quantifier follows nothing in regex; marked by <-- HERE in m/# using defaults found in .config
* <-- HERE 
*
Options:
(?msx-i:(>|\s)) 1. opt1
(?msx-i:(>|\s)) 2. opt2
choice[1-2?]: / at ./so.pl line 14.

Попытка уйти от звездочек приводит к неудачному совпадению (выход D'oh). Попытка избежать других надоедливых символов также приводит к неудачному совпадению. Я мог бы продолжать пробовать разные комбинации того, что нужно для побега, но здесь есть много вариантов, и я надеюсь, что кто-то сможет дать некоторое представление.


person Erik Johansen    schedule 14.11.2008    source источник


Ответы (3)


Вы должны экранировать разделитель для qr//, и вы должны экранировать любые метасимволы регулярных выражений, которые вы хотите использовать в качестве литералов. Если вы хотите, чтобы они были буквальными *, вам нужно их экранировать, поскольку * является квантификатором регулярного выражения.

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

Это то, что вы хотите, с удаленными флагами регулярных выражений и экранированием правильных вещей:

my $sc = qr{(>|\s)};

my $re = qr{# using defaults found in \.config
\*
\*
Options:
$sc 1\. opt1
$sc 2\. opt2
choice\[1-2\?]: };

Хотя Дамиан Конвей советует людям в разделе Perl Best Practices всегда включать эти параметры в свои регулярные выражения, теперь вы понимаете, почему он ошибается. Вы должны добавлять их только тогда, когда вам нужно то, что они делают, и вы должны добавлять вещи только тогда, когда знаете, что они делают. :) Вот что вы можете сделать, если хотите использовать /x. Вы должны экранировать любые буквальные пробелы, вам нужно как-то обозначить окончания строк, и вы должны экранировать буквальный символ #. То, что раньше было читабельно, теперь беспорядок:

my $sc  = qr{(>|\s)};
my $eol = qr{[\r\n]+};

my $re  = qr{\# \s+ using \s+ defaults \s+ found \s+ in \s+ \.config $eol
\*                    $eol
\*                    $eol
Options:              $eol
$sc \s+ 1\. \s+ opt1   $eol
$sc \s+ 2\. \s+ opt2   $eol
choice\[1-2\?]: \s+
}x;

if ( $output =~ $re ) {
  print "OK!\n";
}
else {
  print "D'oh!\n";
}
person brian d foy    schedule 14.11.2008
comment
Арх! Мое понимание того, что сделали «s» и «x», было обратным реальности. Следовательно, 's' отсутствует в $re. Но да, я виню здесь и PbP. :) - person Erik Johansen; 14.11.2008
comment
Книга объясняет, что делают опции и зачем их использовать... вы не можете винить в этом книгу. :) - person Brian Carper; 14.11.2008
comment
Я могу винить книгу. В нем говорится: Всегда используйте флаг /x (стр. 236) и Всегда используйте флаг /m (стр. 237). Рекомендация Always неверна. - person brian d foy; 14.11.2008
comment
Вина лежит исключительно на мне :). Быстрое редактирование моего .perlcriticrc должно исправить это. - person Erik Johansen; 15.11.2008

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

Чтобы ответить на ваш вопрос напрямую (однако), в дополнение к символу без кавычек (в данном случае }) вам нужно как минимум экранировать .[$()|*+?{\

person geocar    schedule 14.11.2008
comment
На самом деле, это используется в сочетании с Expect и Test::More. Просто сократите код для примера. - person Erik Johansen; 14.11.2008

Как сказал Брайан, вы должны избегать метасимволов разделителя и регулярного выражения. Обратите внимание, что при использовании qr//x (которым вы являетесь) вы также должны экранировать символы пробела и # (который является маркером комментария). Вы, вероятно, на самом деле не хотите использовать /x здесь. Если вы хотите быть в безопасности, вы можете экранировать любой небуквенно-цифровой символ.

person cjm    schedule 14.11.2008