PAYATHON 2026

pyparsing 如何让 SUB 语法优先于模型名匹配?

数据小陈

结论

scanString() 会从左到右查找匹配项。modelExtract1 | modelExtract2 中的 | 是 MatchFirst,只决定同一起始位置上备选项的匹配顺序。它不会让扫描器跳过已经匹配成功的 B2 X=2,转而优先选择后面的 SUB [mname2]。

可以在第一种语法前加一个零宽负向前瞻:如果从当前扫描位置到本行末尾还能找到 SUB [,就不匹配普通模型名语法。这样,第二行会跳过 B2,再由 modelExtract2 提取 mname2。

示例

from pyparsing import (
    Combine,
    Literal,
    OneOrMore,
    Regex,
    Word,
    alphanums,
    alphas,
    nums,
)

cdl = """
A1 B1 C1 mname1 X=1 Y=2
A2 B2 X=2 SUB [mname2] C2
"""

ident = Word(alphas, alphanums)
intgr = Word(nums)
paramAssign = Combine(ident + Literal("=") + intgr)

# 从当前扫描位置开始,如果本行后面还有 SUB [,则不允许匹配普通模型名。
no_later_sub = ~Regex(r".*\bSUB\s*\[")

modelExtract1 = (
    no_later_sub
    + ident("modelName")
    + OneOrMore(paramAssign)
)

modelExtract2 = (
    Regex(r"\bSUB\s*\[\s*")
    + ident("modelName")
)

modelExtract = modelExtract1 | modelExtract2

for line in cdl.splitlines():
    for match, start, stop in modelExtract.scanString(line):
        print(match.modelName)

输出:

mname1
mname2

这里的 ~Regex(...) 是零宽负向前瞻,只检查当前位置后面的文本,不会消耗字符。扫描第二行到 B2 时,前瞻发现后面还有 SUB [,所以第一种语法匹配失败。扫描继续到 SUB 后,第二种语法匹配并提取 mname2。

适用条件

这种写法假设 SUB [ 是区分两种语法的标记,并且每次只扫描一行。如果 CDL 语法允许注释或字符串中出现 SUB [,简单的正则前瞻也可能将其识别为标记。此时应先按语言规则排除注释和字符串,或解析整行结构后再判断。示例中的标识符和参数规则也经过简化,需要根据实际 CDL 定义补全。

备注:内容仅供参考。