Как аккуратно сопоставить «x» и «[x]» с регулярным выражением без повторения? - PullRequest
7 голосов
/ 26 июня 2011

Я пишу регулярное выражение Perl, чтобы соответствовать обеим строкам x bla и [x] bla. Один из вариантов - /(?:x|\[x\]) bla/. Это нежелательно, потому что в реальном мире x сложнее, поэтому я хочу избежать повторения.

Лучшее решение на данный момент - поместить x в переменную и предварительно скомпилировать регулярное выражение:

my $x = 'x';
my $re = qr/(?:$x|\[$x\]) bla/o;

Есть ли более аккуратное решение? В этом случае удобочитаемость важнее производительности.

Ответы [ 5 ]

9 голосов
/ 26 июня 2011

Возможно, но не все так чисто.Вы можете использовать тот факт, что условные подшаблоны поддерживают такие тесты, как (?(N)), чтобы проверить, что N-й поднабор захвата успешно соответствует.Таким образом, вы можете использовать выражение, такое как /(\[)?X(?(1)\])/, чтобы соответствовать '[X]' или 'X'.

1 голос
/ 27 июня 2011

Я протестировал решение /(\[)?X(?(1)\])/ (которое набрало 7 баллов), и оно также соответствовало [X и X], что неверно. Оригинальный плакат /(?:$x|\[$x\]) bla/ действительно работает, для чего требуются либо совпадающие скобки, либо ни одного.

1 голос
/ 26 июня 2011

На самом деле нет более изящного решения, потому что именно здесь мы покидаем область обычных языков и начинаем требовать более сложного автомата с некоторой памятью. (Обратные ссылки сделали бы это, за исключением того, что обратная ссылка расширяется до буквального совпадения с предыдущей частью строки, а не до « this , но только если , что было сопоставлено».)

Иногда вместо этого можно использовать двухэтапный процесс, заменяя сложный X единственным символом, который, как известно, не присутствует в исходном тексте (для этого могут использоваться управляющие символы), что позволяет упростить второй этап матч. Не всегда возможно, хотя; зависит от того, что вы подходите.

1 голос
/ 26 июня 2011

Вы можете написать что-то вроде (\[)?x(??{ defined $1 ? "]" : "" }), но, вероятно, не стоит.

1 голос
/ 26 июня 2011

Вы также можете предварительно скомпилировать $x.Это также делает ошибки немного более очевидными, если $x действительно ?(+[*{ или что-то еще, от чего компилятор регулярных выражений будет полностью сходить с ума.

my $x = qr/x/;
my $re = qr/(?:$x|\[$x\]) bla/o;
...