Переведите назначение этого регулярного выражения PHP для многострочных строк в Python/PERL.

Ниже приведено регулярное выражение PHP, предназначенное для сопоставления (многострочных) строк внутри исходного кода PHP или JavaScript (из этот пост), но я подозреваю, что в нем есть проблемы. Что такое буквальный Python (или еще PERL) эквивалент этого?

~'(\\.|[^'])*'|"(\\.|[^"])*"~s
  • модификатор s означает, что точка соответствует всем символам, включая новая линия; в Python это re.compile(..., re.DOTALL)
  • Я совершенно не понимаю намерения ведущего \\. ? Это уменьшает до . ? Двойная обратная косая черта должна дважды экранировать ее в PHP?
  • разрешение в каждой позиции совпадения \\. или [^'] (любой символ без кавычек) кажется мне полным излишеством, возможно, это объясняет, почему регулярное выражение этого человека взрывается. Разве группа [^'] уже не соответствует всему, что делает . с модификатором s, наверняка она должна соответствовать новым строкам?

  • для создания двух версий регулярного выражения с одинарными и двойными кавычками в Python можно использовать этот двухэтапный подход

  • Обратите внимание, что более простую версию этого регулярного выражения также можно найти в списке примеров регулярных выражений PHP в разделе Программирование: Строка.


person smci    schedule 09.08.2011    source источник
comment
Я только что перечитал вопрос, и теперь я в замешательстве. В той другой теме вы искали регулярные выражения, которые могут привести к зависанию или сбою системы, и это регулярное выражение было одним из ответов. Что ты после этого времени? Вы хотите улучшить регулярное выражение или просто хотите выяснить, не вязнет ли оно в Python так же, как в PHP?   -  person Alan Moore    schedule 11.08.2011
comment
@Alan, этот вопрос означает именно то, что он говорит: объясните назначение регулярного выражения PHP ЭТОГО парня, то есть каким именно многострочным строкам соответствует это регулярное выражение. Это все.   -  person smci    schedule 11.08.2011


Ответы (2)


Регулярное выражение в основном нормальное, за исключением того, что оно не обрабатывает экранированные кавычки (т. е. \" и \'). Это достаточно легко исправить:

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

Это «общее» регулярное выражение; в Python вы обычно записываете это в виде необработанной строки:

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

В PHP вам нужно экранировать обратную косую черту, чтобы они прошли обработку строк PHP:

'~\'(?:\\\\.|[^\'\\\\]+)*\'|"(?:\\\\.|[^"\\\\]+)*"~s'

Большинство популярных в настоящее время языков имеют либо строковый тип, требующий меньше экранирования, либо поддержку литералов регулярных выражений, либо и то, и другое. Вот как ваше регулярное выражение будет выглядеть как дословная строка C#:

@"'(?:\\.|[^'\\]+)*'|""(?:\\.|[^""\\]+)*"""

Но, если оставить в стороне соображения форматирования, само регулярное выражение должно работать в любом варианте, производном от Perl (а также во многих других вариантах).


p.s.: Обратите внимание, как я добавил квантификатор + к вашим классам персонажей. Ваша интуиция о сопоставлении одного символа за раз верна; добавление + дает огромную разницу в производительности. Но не позволяйте этому обмануть вас; когда вы имеете дело с регулярными выражениями, интуиция чаще ошибается, чем нет. :/

person Alan Moore    schedule 10.08.2011
comment
Исходное регулярное выражение обрабатывает экранированные кавычки, \\. будет соответствовать перед [^'], так что все работает нормально. Ваша точка зрения об улучшении производительности за счет добавления + верна, но только тогда также необходимо исключить обратную косую черту в классах символов. - person Long Ears; 10.08.2011
comment
@Long Ears: это нормально для правильно сформированных строковых литералов, но также соответствует вещам, которым не следует, например "\". Сначала вариант \\. соответствует варианту \", но это не оставляет ничего для соответствия окончательному варианту ". Таким образом, он отступает и позволяет альтернативе [^.] вместо этого соответствовать обратной косой черте, и Боб - ваш дядя! - person Alan Moore; 11.08.2011
comment
Что ж, если вы принимаете во внимание искаженный исходный код, вам следует использовать полный лексер, а не простое регулярное выражение. Отсутствие совпадений не означает правильность в любом случае;) - person Long Ears; 11.08.2011
comment
@Long: я не думаю, что OP действительно использует его для этой цели, но я не уверен, какова цель . - person Alan Moore; 11.08.2011

\\. предназначен для соответствия буквальному обратному слэшу в шаблоне и проглатыванию следующего символа. Обратите внимание: поскольку шаблоны в PHP (и Python) содержатся в строках, на самом деле он должен быть \\\\. в строке, чтобы в регулярном выражении он заканчивался как \\..

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

Этот шаблон выглядит так, как будто он должен работать нормально, и я не могу придумать более краткого способа выразить его.

Он также должен нормально работать в Python (как вы говорите, с re.DOTALL). В Python вы можете использовать нотацию исходной строки, чтобы сохранить дополнительное экранирование обратной косой черты, хотя вам все равно нужно экранировать одинарную кавычку. Это должно быть эквивалентно:

re.search(r'\'(\\.|[^\'])*\'|"(\\.|[^"])*"', str, re.DOTALL)

person Long Ears    schedule 09.08.2011