В моем приложении Python мне нужно написать регулярное выражение, которое соответствует циклу C ++ for
или while
, который завершается точкой с запятой (;
). Например, оно должно соответствовать этому:
for (int i = 0; i < 10; i++);
... но не это:
for (int i = 0; i < 10; i++)
Это выглядит тривиально на первый взгляд, пока вы не поймете, что текст между открывающей и закрывающей скобками может содержать другие скобки, например:
for (int i = funcA(); i < funcB(); i++);
Я использую модуль python.re. Прямо сейчас мое регулярное выражение выглядит следующим образом (я оставил свои комментарии, чтобы вам было легче понять):
# match any line that begins with a "for" or "while" statement:
^\s*(for|while)\s*
\( # match the initial opening parenthesis
# Now make a named group 'balanced' which matches a balanced substring.
(?P<balanced>
# A balanced substring is either something that is not a parenthesis:
[^()]
| # …or a parenthesised string:
\( # A parenthesised string begins with an opening parenthesis
(?P=balanced)* # …followed by a sequence of balanced substrings
\) # …and ends with a closing parenthesis
)* # Look for a sequence of balanced substrings
\) # Finally, the outer closing parenthesis.
# must end with a semi-colon to match:
\s*;\s*
Это прекрасно работает для всех вышеперечисленных случаев, но прерывается, как только вы пытаетесь сделать третью часть цикла for содержащей функцию, например:
for (int i = 0; i < 10; doSomethingTo(i));
Я думаю, что он ломается, потому что, как только вы помещаете какой-то текст между открывающей и закрывающей скобками, «сбалансированная» группа соответствует тексту, и, таким образом, часть (?P=balanced)
больше не работает, так как не будет совпадение (из-за того, что текст внутри скобки отличается).
В своем коде Python я использую флаги VERBOSE и MULTILINE и создаю регулярное выражение следующим образом:
REGEX_STR = r"""# match any line that begins with a "for" or "while" statement:
^\s*(for|while)\s*
\( # match the initial opening parenthesis
# Now make a named group 'balanced' which matches
# a balanced substring.
(?P<balanced>
# A balanced substring is either something that is not a parenthesis:
[^()]
| # …or a parenthesised string:
\( # A parenthesised string begins with an opening parenthesis
(?P=balanced)* # …followed by a sequence of balanced substrings
\) # …and ends with a closing parenthesis
)* # Look for a sequence of balanced substrings
\) # Finally, the outer closing parenthesis.
# must end with a semi-colon to match:
\s*;\s*"""
REGEX_OBJ = re.compile(REGEX_STR, re.MULTILINE| re.VERBOSE)
Может кто-нибудь предложить улучшение этого регулярного выражения? Мне становится слишком сложно обдумывать.