Lark 匹配自定义分隔符多行字符串

Lark matching custom delimiter multiline strings

我正在尝试使用 lark 从 perl 文件中提取一些信息。为此,我需要对语句是什么有一个基本的了解。我遇到的问题是“Here Document”字符串。我会将它们描述为带有自定义分隔符的多行字符串,例如:

$my_var .= << 'anydelim';
some things
other things
anydelim

在写下这个问题时,我想出了一个使用带有反向引用/命名引用的正则表达式的解决方案。由于我找不到任何类似的问题,所以我决定post这个问题并自己回答。

如果有人知道任何其他方法(例如跨多个百灵鸟规则使用反向引用的方法),请告诉我!

使用正则表达式的解决方案。主要成分:

  • 反向引用,在本例中命名为引用
  • /s 修饰符(导致 . 也匹配换行符
  • .*?匹配非贪婪(否则它也会消耗分隔符)
from lark import Lark

block_grammar = r"""
    %import common.WS
    %ignore WS
    delimited_string: "<<" /(?P<quote>['"])(?P<delimiter>[A-Za-z_]+)(?P=quote)\;.*?(?P=delimiter)/s
"""
minimal_parser = Lark(block_grammar, start="delimited_string")

ast = minimal_parser.parse(r"""
    << 'SomeDelim'; fasdfasdf 
    fddfsdg SomeDelim
""")
print(ast.pretty())

如果您想跨多个终端进行复杂的反向引用,例如您不能使用单个正则表达式,您需要使用 PostLexer(或者最坏的情况是自定义词法分析器)。一个 XML 结构的小例子:

<html>
    <body>
        Hello World
    </body>
</html>

可以被这个语法 + Postlexer 解析(验证):

from typing import Iterator

from lark import Lark, Token

TEXT = r"""
<html>
    <body>
        Hello World
    </body>
</html>
"""

GRAMMAR = r"""
start: node

node: OPEN_TAG content* CLOSE_TAG
content: node
       | TEXT 

TEXT: /[^\s<>]+/
RAW_OPEN: "<" /\w+/ ">"
RAW_CLOSE: "</" /\w+/ ">"

%ignore WS

%import common.WS

%declare OPEN_TAG CLOSE_TAG
"""


class MatchTag:
    always_accept = "RAW_OPEN", "RAW_CLOSE"

    def process(self, stream: Iterator[Token]) -> Iterator[Token]:
        stack = []
        for t in stream:
            if t.type == "RAW_OPEN":
                stack.append(t)
                t.type = "OPEN_TAG"
            elif t.type == "RAW_CLOSE":
                open_tag = stack.pop()
                if open_tag.value[1:-1] != t.value[2:-1]:
                    raise ValueError(f"Non matching closing tag (expected {open_tag.value!r}, got {t.value!r})")
                t.type = "CLOSE_TAG"
            yield t


parser = Lark(GRAMMAR, parser='lalr', postlex=MatchTag())

print(parser.parse(TEXT).pretty())

(注意:如果你真的想解析,请不要使用 Lark XML。有很多难以处理甚至无法处理的陷阱)