为什么Lark将名称拆分为单个字符?

0 投票
1 回答
38 浏览
提问于 2025-04-14 16:31

我正在尝试解析一段简单的文本,内容如下:

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

这样就解决了你遇到的问题。

撰写回答