簡體   English   中英

在PyParsing中不是那么簡單的遞歸下降

[英]Not so simple recursive descent in PyParsing

我需要以下需要解析的測試用例(模式)的幫助(在python中):

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

and are identifiers and is identifier (macro definition) or number or function or numeric expression. 其中標識符,是標識符(宏定義)或數字或函數或數字表達式。

is a function, for eg 我可以將其拆分相對容易(即使使用重復的RE組),但是函數的情況除外,例如

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

ps括號,分號和逗號之間可以有零個或多個空格。

也許可以用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']]]]]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM