Python PLY Lex正则匹配异常求助:TypeError未知文本问题
问题分析与解决方案
你的PLY Lex解析器出问题的核心原因是正则表达式中的^符号没有按你预期的方式工作。
在默认的正则模式下,^只会匹配整个输入字符串的起始位置,而不是每行的开头。你的原代码中,第一个#行能匹配成功是因为它刚好在输入的最开始,但后续的#行因为不是整个输入的开头,所以t_COMMENT的^\#.*\n根本匹配不到;同样,t_OTHER的^[^\#].*\n也只能匹配输入开头的非#行,后面的非#行同样无法被匹配。这些未被匹配的字符会不断累积,最终触发t_error抛出异常。
修复方案
我们需要启用正则的多行模式,让^匹配每行的开头,$匹配每行的结尾。有两种方式可以实现:
方式1:在正则中添加多行修饰符(?m)
修改你的正则表达式,给每个token的规则加上(?m)前缀,这样就能让^和$作用于每行:
from ply import lex tokens = ( 'COMMENT', 'OTHER' ) # (?m)启用多行模式,^匹配每行开头,匹配整行注释 t_COMMENT = r'(?m)^#.*\n' # 匹配每行开头非#的整行内容 t_OTHER = r'(?m)^[^#].*\n' def t_error(t): # 处理空行(仅含换行符)的情况,避免触发错误 if t.value[0] == '\n': t.lexer.skip(1) else: raise TypeError("Unknown text '%s'" % (t.value,)) # 初始化lexer lexer = lex.lex() # 你的输入内容 input_text = """# This is a real comment #And this one also #/* # * # *Variable de feeu # */ ma_var: True It is done, over, kaput """ # 解析并输出结果 lexer.input(input_text) for tok in iter(lexer.token, None): print(repr(tok.type), repr(tok.value))
方式2:全局启用多行模式
在调用lex.lex()时传入reflags=re.MULTILINE参数,这样所有正则规则都会自动应用多行模式:
import re from ply import lex tokens = ( 'COMMENT', 'OTHER' ) # 现在^会匹配每行开头 t_COMMENT = r'^#.*\n' t_OTHER = r'^[^#].*\n' def t_error(t): if t.value[0] == '\n': t.lexer.skip(1) else: raise TypeError("Unknown text '%s'" % (t.value,)) # 全局启用多行模式 lexer = lex.lex(reflags=re.MULTILINE) # 输入和解析部分与方式1一致
额外说明
- 我在
t_error中添加了对空行的处理:如果遇到单独的换行符,直接跳过,避免因为空行触发错误。 - PLY的token匹配规则是最长匹配优先,如果多个规则都能匹配,会选择最长的那个;长度相同时,先定义的规则优先。这里我们的两个规则都是匹配整行,长度一致,所以先定义的
COMMENT会优先匹配,符合你的需求。
运行修改后的代码,就能正确解析所有的注释行和非注释行啦!
内容的提问来源于stack exchange,提问作者Raoul Debaze
相关产品推荐
相关产品推荐

