Какие символы я должен экранировать в скомпилированном регулярном выражении Perl? - PullRequest
5 голосов
/ 14 ноября 2008

Мне трудно определить, какие символы должны экранироваться при использовании конструкции 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). Попытка избежать других досадных символов также приводит к неудачному совпадению. Я мог бы продолжать пробовать разные комбинации того, что можно избежать, но здесь есть много вариантов, и я надеюсь, что кто-то может дать некоторое представление.

Ответы [ 3 ]

14 голосов
/ 14 ноября 2008

Вы должны экранировать разделитель для 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 , что эти опции всегда должны быть в их регулярных выражениях, теперь вы понимаете, почему он не прав. Вы должны добавлять их только тогда, когда вы хотите, чтобы они делали, и вы должны добавлять вещи, только когда знаете, что они делают. :) Вот что вы можете сделать, если вы хотите использовать / х. Вы должны избегать любых буквальных пробелов, вам нужно как-то обозначать окончания строк, и вы должны избегать буквального символа #. То, что раньше было читаемым, теперь беспорядок:

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";
}
7 голосов
/ 14 ноября 2008

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

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

2 голосов
/ 14 ноября 2008

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

...