RegEx со странным поведением: сопоставление String с обратной ссылкой для разрешения экранирования и одиночных и двойных кавычек - PullRequest
2 голосов
/ 25 октября 2010

Совпадение строки, которая позволяет экранировать, не так сложно. Смотрите здесь: http://ad.hominem.org/log/2005/05/quoted_strings.php. Для простоты я выбрал подход, в котором строка делится на два «атома»: либо символ, который не является «кавычкой или обратной косой чертой», либо обратный слеш, за которым следует любой символ.

"(([^"\\]|\\.)*)"

Очевидное улучшение теперь в том, чтобы разрешить разные цитаты и использовать обратную ссылку.

(["'])((\\.|[^\1\\])*?)\1

Также множественные обратные слеши интерпретируются правильно.

Теперь перейдем к той части, где это становится странным: мне нужно проанализировать некоторые переменные, подобные этой (обратите внимание на отсутствующую обратную косую черту в первом значении переменной):

test = 'foo'bar'
var = 'lol'
int = 7

Так что я написал довольно выражение. Я обнаружил, что следующая часть не работает должным образом (единственное отличие от приведенного выше выражения заключается в добавлении "([\ r \ n] +)"):

(["'])((\\.|[^\1\\])*?)\1([\r\n]+)

Несмотря на отсутствие обратной косой черты, 'foo'bar' соответствует. Я использовал RegExr от gskinner для этого (онлайн-инструмент), но PHP (PCRE) ведет себя так же.

Чтобы это исправить, вы можете жестко закодировать цитату, заменив обратные ссылки на '. Тогда это работает как ожидалось. Означает ли это, что обратная ссылка на самом деле не работает в этом случае? И какое это имеет отношение к символам перевода строки, без них это работало?

1 Ответ

2 голосов
/ 25 октября 2010

Вы не можете использовать обратную ссылку внутри класса символов; \1 будет интерпретироваться как восьмеричное 1 в этом случае (по крайней мере, в некоторых движках регулярных выражений, я не знаю, если это универсально верно).

Вместо этого попробуйте следующее:

(["'])(?:\\.|(?!\1).)*\1(?:[\r\n]+)

или, как многословное регулярное выражение:

(["'])       # match a quote
(?:          # either match...
 \\.         # an escaped character
 |           # or
 (?!\1).     # any character except the previously matched quote
)*           # any number of times
\1           # then match the previously matched quote again
(?:[\r\n]+)  # plus one or more linebreak characters.

Редактировать: Удалены некоторые ненужные скобки и заменены некоторые на не захватывающие скобки.

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

Также обратите внимание, что вам не нужно делать * ленивым, чтобы это работало - регулярное выражение не может пересекать символ кавычки без экранирования - и что вам не нужно проверять обратную косую черту во второй части чередование, так как все обратные слеши уже были найдены первой частью чередования (?:\\.|(?!\1).). Вот почему эта часть должна быть первой.

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