#ply
Вопрос:
Я пишу простой синтаксический анализатор, используя PLY. Мои комментарии могут выглядеть так
# this is a single line comment with an escaped new line
Моя попытка состоит в том, чтобы использовать здесь состояния. У меня есть
states = ( ('COMMENT', 'exclusive'), ) tokens = ('COMMENT') def t_begin_COMMENT(t): r'#' t.lexer.begin('COMMENT') def t_COMMENT_contents(t): r'.|\n' t_COMMENT_ignore = r' ' def t_COMMENT_error(t): pass def t_COMMENT_end(t): r'n' t.lexer.begin('INITIAL')
Когда я это сделаю
lexer = lex.lex() string = "# test \ns n4" lexer.input(string) for tok in lexer: print(tok)
он должен напечатать 4 (у меня есть для этого другой токен, но сейчас это не имеет значения), но я получаю s
и 4
где s
все еще комментарий. Как мне написать регулярное выражение для содержимого? Это потому COMMENT
, что заканчивается n
?
Ответ №1:
Регулярные выражения Python не дают самого длинного совпадения. Чередование ( |
) в регулярном выражении Python упорядочено; если вы используете шаблон .|\n
, то .
он всегда будет совпадать (если только строка не пуста), и поэтому \n
никогда не будет опробован. Это легче увидеть без символов escape:
gt;gt;gt; import re gt;gt;gt; re.match(r'.|ab', 'ab') lt;_sre.SRE_Match object; span=(0, 1), match='a'gt; gt;gt;gt; re.match(r'ab|.', 'ab') lt;_sre.SRE_Match object; span=(0, 2), match='ab'gt;
Мне совсем не понятно, почему вы хотите проделать всю эту работу, а не использовать одно регулярное выражение без необходимости прибегать к состояниям лексера.
def t_comment(t): r'#(\n|.)*n' pass
(Примечание: я бы предпочел регулярное выражение r'#(\[sS]|.)*'
, которое позволяет a
избежать чего угодно, в том числе самого себя. Регулярное выражение, которое вы используете, не позволяет вам когда-либо ставить обратную косую черту в конце строки комментария:
# This will continue, perhaps unexpectedly: \ still a comment
Кроме того, трейлинг n
в любом случае будет проигнорирован, поэтому нет очевидной причины включать его в шаблон, где он может не совпадать, если комментарий находится в самом конце ввода и ввод не заканчивается новой строкой.
Комментарии:
1. Я привык к состояниям, потому что в основном я использую Flex. Спасибо за разъяснение, я не знал, что это изменение было заказано.
2. @Awerde: Я бы использовал точно такое же регулярное выражение в flex. Нет смысла использовать состояния только для того, чтобы избежать операторов повторения.
3. Конечно, в Flex вам не нужно беспокоиться о упорядоченном чередовании. Это «попалось» с Python и другими движками регулярных выражений, совместимыми с Perl. Я считаю, что Javascript-это то же самое. Регулярные выражения Flex используют правила Posix (такие же, как grep), где чередование не упорядочено.