gpt4 book ai didi

python - PyParsing 中的递归下降并不是那么简单

转载 作者:行者123 更新时间:2023-12-01 04:47:17 25 4
gpt4 key购买 nike

我需要以下测试用例(模式)的帮助,需要解析(在 python 中):

IO_SET(BLOCK, key1, value1, key2, value2, ... ,keyn, valuen);

其中BLOCKkey标识符value是标识符(宏定义)或数字或函数或数值表达式。

我可以相对容易地分割它(即使是重复的 RE 组),除了 value 是一个函数的情况,例如

IO_SET(BLOCK, key1, function(1+2,3, val11), key2, val2, key3, (3U)+cVAL3); 

附:括号、分号和逗号周围允许有零个或多个空格。

也许这可以通过 pyparsing 来完成,但我遇到了很多问题,例如value = Word(nums) 单词“1a23”被解析为 value = “1”

最佳答案

这是您的示例的解析器。您必须定义递归语法(使用 pyparsing Forward),因为函数调用可以具有本身就是函数调用的参数:

sample = """IO_SET(BLOCK, key1, function(1+2,3, val11), key2, val2, key3, (3U)+cVAL3);"""


from pyparsing import *

SEMI,LPAREN,RPAREN = map(Suppress,";()")
identifier = Combine(Optional(Word(nums+'_')) + Word(alphas, alphanums+'_'))
integer= Combine(Optional('-') + Word(nums))
realnum = Combine(integer.copy() + '.' + Optional(Word(nums)))

fn_call = Forward()
# this order is *critical*
value = realnum | fn_call | identifier | integer

expr = infixNotation(value,
[
(oneOf('* /'), 2, opAssoc.LEFT),
(oneOf('+ -'), 2, opAssoc.LEFT),
])
fn_call <<= Group(identifier + LPAREN + Group(Optional(delimitedList(expr))) + RPAREN)


print value.parseString(sample).asList()

打印:

[['IO_SET', ['BLOCK', 'key1', ['function', [['1', '+', '2'], '3', 'val11']], 
'key2', 'val2', 'key3', ['3U', '+', 'cVAL3']]]]

如注释中所示,值中表达式的顺序至关重要。由于该语言支持以数字字符开头的标识符,因此您必须在测试整数之前测试 和 标识符(否则前导数字将被解释为整数,而字符串的其余部分将悬空)。

您可以尝试一些替代方法来依赖此顺序:

  • 使用 Or 运算符 ('^') 而不是 MatchFirst ('|'),它将尝试所有 个可能的替代方案并选择最长的匹配(可以在递归语法中无限递归,例如这个)

  • 强制整数后面跟一个分词符(使用 pyparsing 的 WordEnd() 类)

HTH

编辑

这是更新版本,其中包含您澄清的定义。由于您的整数形式有一个明确的正则表达式,因此最简单的方法是使用 pyparsing Regex 类;通过这一更改,我将 identifier 恢复为更传统的形式。我还向函数参数添加了键值结构,但必须定义两种函数调用,因为您的参数函数调用不符合结构化参数列表。使用新的 pprint 方法可以更轻松地查看您的 arg 列表结构。

sample = """IO_SET(BLOCK, key1, function(1+2,3, val11), key2, val2, key3, (3U)+cVAL3);"""

from pyparsing import *

SEMI,LPAREN,RPAREN,COMMA = map(Suppress,";(),")
#identifier = Combine(Optional(Word(nums+'_')) + Word(alphas, alphanums+'_'))
identifier = Word(alphas, alphanums+'_')
#integer= Combine(Optional('-') + Word(nums))
integer = Regex(r"[+-]?\d+[Uu]?[Ll]?")
realnum = Combine(integer.copy() + '.' + Optional(Word(nums)))

fn_call1 = Forward()
fn_call2 = Forward()
# this order is *critical*
value = realnum | fn_call1 | fn_call2 | identifier | integer

expr = infixNotation(value,
[
(oneOf('* /'), 2, opAssoc.LEFT),
(oneOf('+ -'), 2, opAssoc.LEFT),
])
key_value = Group(identifier + COMMA + expr)
kv_args = identifier + Optional(COMMA + delimitedList(key_value))
fn_call1 <<= Group(identifier + LPAREN + Group(kv_args) + RPAREN)
simple_args = Optional(delimitedList(expr))
fn_call2 <<= Group(identifier + LPAREN + Group(simple_args) + RPAREN)

value.parseString(sample).pprint()

打印:

[['IO_SET',
['BLOCK',
['key1', ['function', [['1', '+', '2'], '3', 'val11']]],
['key2', 'val2'],
['key3', ['3U', '+', 'cVAL3']]]]]

关于python - PyParsing 中的递归下降并不是那么简单,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29171433/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com