我需要帮助以下需要解析的测试用例(模式)(在python中):
IO_SET(BLOCK, key1, value1, key2, value2, ... ,keyn, valuen);
其中 BLOCK 和 key 是标识符而值是标识符(宏定义)或数字或函数或数字表达。
我可以相对容易地拆分它(即使是重复的RE组),除了值是函数的情况,例如
IO_SET(BLOCK, key1, function(1+2,3, val11), key2, val2, key3, (3U)+cVAL3);
P.S。允许括号,分号和逗号周围有零个或多个空格。
可能这可以通过pyparsing来完成,但是我遇到了很多问题,例如在遇到问题的情况下
value = Word(nums)
一个字" 1a23"被解析为value = "1"
答案 0 :(得分:2)
这是您的示例的解析器。你必须定义一个递归语法(使用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']]]]]