为什么Lark将名称拆分为单个字符?
我正在尝试解析一段简单的文本,内容如下:
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
现在如果我打印并美化输出,'name'就会被分成不同的部分:
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'当作一个字符串,而不是分开的字符……
1 个回答
1
发生了什么
Lark在处理非终结符和终结符时使用了不同的命名规则。定义一个非终结符时,你需要用小写字母。而如果你想定义一个终结符,就应该使用大写字母。
因为有这个区别,lark会把标记name
当作非终结符来处理,使用的生成规则是:
(LETTER | DIGIT | "_")+
这会导致你在输出中看到的树状结构:
name
a
b
c
如何解决
其实你并不想要树状结构,而是想要一个单独的标记,所以你应该把它改成一个终结符。这意味着你需要把标记name
改成NAME
。这样做后,你就告诉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
运行这个会得到以下输出:
Tree(Token('RULE', 'test'), [Token('NAME', 'abc')])
test abc
这样就解决了你遇到的问题。