如何用PLY解析含嵌套匹配括号的最大分组令牌?
解决PLY中嵌套括号最大分组的令牌匹配问题
好问题!确实,PLY依赖的标准Python re 模块不支持递归正则,想靠单一正则直接生成嵌套括号的令牌是行不通的。不过咱们有个非常优雅的办法——不用在语法解析的p_*函数里手动写嵌套逻辑,而是靠PLY的**词法状态机(Lex States)**就能搞定:
核心思路:用状态机跟踪括号层级
PLY支持定义专属的词法状态,我们可以利用这个特性:遇到左括号时切换到“括号内部”状态,然后跟踪括号的嵌套层级——每遇到一个左括号就增加层级,遇到右括号就减少层级,当层级回到0时,就说明找到了一个完整的、包含嵌套的括号分组,此时生成对应的令牌即可。
下面是完整的代码示例:
import ply.lex as lex # 定义词法状态:inparens是专属状态,只会处理括号内的内容 states = ( ('inparens', 'exclusive'), ) # 定义需要识别的令牌类型 tokens = ( 'IDENTIFIER', 'PAREN_GROUP', ) # -------------------------- 初始状态的规则 -------------------------- # 匹配标识符(比如例子中的'a') def t_IDENTIFIER(t): r'[a-zA-Z_][a-zA-Z0-9_]*' return t # 遇到左括号,切换到括号内部状态,初始化层级和文本缓存 def t_LPAREN(t): r'\(' t.lexer.begin('inparens') t.lexer.paren_count = 1 t.lexer.paren_text = '(' # -------------------------- 括号内部状态的规则 -------------------------- # 遇到左括号,层级+1,把字符加入缓存 def t_inparens_LPAREN(t): r'\(' t.lexer.paren_count += 1 t.lexer.paren_text += '(' # 遇到右括号,层级-1,把字符加入缓存;层级回到0时生成令牌并切回初始状态 def t_inparens_RPAREN(t): r'\)' t.lexer.paren_count -= 1 t.lexer.paren_text += ')' if t.lexer.paren_count == 0: t.type = 'PAREN_GROUP' t.value = t.lexer.paren_text t.lexer.begin('INITIAL') return t # 匹配括号内部的其他所有非括号字符(比如|、字母、数字等),直接加入缓存 def t_inparens_OTHER(t): r'[^()]+' t.lexer.paren_text += t.value # -------------------------- 通用规则 -------------------------- # 忽略空白字符(按需调整) t_ignore = ' \t\n' t_inparens_ignore = ' \t\n' # 错误处理函数 def t_error(t): print(f"非法字符: {t.value[0]}") t.lexer.skip(1) def t_inparens_error(t): print(f"括号内的非法字符: {t.value[0]}") t.lexer.skip(1) # -------------------------- 测试代码 -------------------------- if __name__ == '__main__': lexer = lex.lex() test_cases = ["a(b|c(d|e))", "a(b)(c)(d)"] for case in test_cases: print(f"\n测试用例: {case}") lexer.input(case) while True: tok = lexer.token() if not tok: break print(f"令牌类型: {tok.type}, 内容: {tok.value}")
效果验证
运行这段代码后,你会看到:
- 对于
a(b|c(d|e)),输出两个令牌:IDENTIFIER(a)和PAREN_GROUP((b|c(d|e))),正好匹配'a'之后的全部嵌套括号内容 - 对于
a(b)(c)(d),会输出四个令牌:IDENTIFIER(a)、PAREN_GROUP((b))、PAREN_GROUP((c))、PAREN_GROUP((d)),符合“独立括号不合并”的要求
这种方式完全在词法分析层面处理了嵌套逻辑,不需要在语法解析函数里手动写递归或层级判断,完美满足你的需求。
内容的提问来源于stack exchange,提问作者lexxish
相关产品推荐
相关产品推荐

