Lark解析器为何将name拆分为单个字符?
问题描述
我尝试解析如下简单文本:
test abc
使用的Lark语法如下:
start: test test: "test" _WSI name _NL name: (LETTER | DIGIT | "_")+ %import common.WS_INLINE -> _WSI %import common.NEWLINE -> _NL %import common.LETTER %import common.DIGIT
但打印并pretty_print解析结果时,name被拆分为单个Token:
Tree(Token('RULE', 'start'), [Tree(Token('RULE', 'test'), [Tree(Token('RULE', 'name'), [Token('LETTER', 'a'), Token('LETTER', 'b'), Token('LETTER', 'c')])])]) start test name a b c
我想知道这是为什么?并希望将name识别为完整字符串而非单个字符。
原因与解决方案
原因
当前语法里的name是语法规则,它由多个基础Token(LETTER/DIGIT/_)组合定义,Lark默认会保留这些基础Token的原始拆分状态,不会自动合并成单个完整字符串。
解决方案
有两种常用方式可以实现将name识别为完整字符串:
- 将
name定义为词法规则
在规则名前加!标记,把name转为词法规则。词法规则会在词法分析阶段优先处理,直接将匹配到的连续字符合并成一个完整Token。修改后的语法如下:
start: test test: "test" _WSI name _NL !name: (LETTER | DIGIT | "_")+ %import common.WS_INLINE -> _WSI %import common.NEWLINE -> _NL %import common.LETTER %import common.DIGIT
- 使用
@merge修饰符
如果不想改动规则类型,可以给name规则添加@merge修饰符,让Lark在解析时自动合并子Token为单个字符串。修改后的语法:
start: test test: "test" _WSI name _NL name@merge: (LETTER | DIGIT | "_")+ %import common.WS_INLINE -> _WSI %import common.NEWLINE -> _NL %import common.LETTER %import common.DIGIT
内容的提问来源于stack exchange,提问作者Grrruk
相关产品推荐
相关产品推荐

