В Perl-выражениях выражения типа \1
, \2
и т.д. обычно интерпретируются как "обратные ссылки" ранее захваченным группам, но не так, когда \1
, \2
и т.д. появляются внутри символа класс. В последнем случае \
рассматривается как escape-символ (и поэтому \1
является просто 1
и т.д.).
Следовательно, если (например) нужно совместить строку (длиной больше 1), первый символ которой соответствует ее последнему символу, но не появляется нигде в строке, следующее регулярное выражение не будет делать:
/\A # match beginning of string;
(.) # match and capture first character (referred to subsequently by \1);
[^\1]* # (WRONG) match zero or more characters different from character in \1;
\1 # match \1;
\z # match the end of the string;
/sx # s: let . match newline; x: ignore whitespace, allow comments
не будет работать, поскольку он соответствует (например) строке 'a1a2a'
:
DB<1> ( 'a1a2a' =~ /\A(.)[^\1]*\1\z/ and print "fail!" ) or print "success!"
fail!
Обычно мне удается найти некоторое обходное решение 1 но оно всегда скорее специфично для задач и обычно гораздо более сложное, чем то, что я буду делать, если бы я мог использовать обратные ссылки в классе символов.
Есть ли общий (и, надеюсь, простой) обходной путь?
1 Например, для проблемы в приведенном выше примере я бы использовал что-то вроде
/\A
(.) # match and capture first character (referred to subsequently
# by \1);
(?!.*\1\.+\z) # a negative lookahead assertion for "a suffix containing \1";
.* # substring not containing \1 (as guaranteed by the preceding
# negative lookahead assertion);
\1\z # match last character only if it is equal to the first one
/sx
... где я заменил достаточно прямое (хотя, увы, неправильное) подвыражение [^\1]*
в более раннем регулярном выражении с несколько более запрещающим отрицательным прогнозом (?!.*\1.+\z)
. Это утверждение в основном говорит "сдаваться, если \1
появляется где-то за пределами этой точки (кроме последней позиции)". Кстати, я даю это решение, чтобы проиллюстрировать подобные обходные пути, о которых я упоминал в вопросе. Я не утверждаю, что он особенно хорош.