【问题标题】:pyparsing: how to parse nested function which start with particular function name?pyparsing:如何解析以特定函数名称开头的嵌套函数?
【发布时间】:2022-11-17 11:04:17
【问题描述】:

我想使用 pyparsing 来解析以特定函数名称开头的嵌套函数。

像这样:

tag("tag_name_1", value_equal("proxy.province", "value", "return_value", test(1,2)))

等待解析的字符串以名为“tag”的函数开头。

问题是为什么表达式堆栈不包含“标签”功能?

import pyparsing as pp
from typing import Any, List, Dict


def debug(*args, **kwargs):
    print("debug"+"---"*10)
    print(*args, **kwargs)
    print("debug"+"---"*10)
    # return "debug"
    return "debug"

def insert_fn_argcount_tuple(t):
    fn = t.pop(0)
    num_args = len(t)
    print((fn, num_args))
    t.insert(0, (fn, num_args))



def push_first(toks):
    exprStack.append(toks[0])


def to_string(toks):
    pass

LPAREN, RPAREN, COMMA = map(pp.Suppress, '(),') 
ident = pp.Word(pp.alphas, pp.alphanums+"_")
integer = pp.Word(pp.nums)
string = (pp.QuotedString("'") | pp.QuotedString('"')).setParseAction()
expr = pp.Forward()
expr_list = pp.delimitedList(pp.Group(expr))
tag_fn = ("tag" + LPAREN + expr_list + RPAREN).setParseAction(insert_fn_argcount_tuple)
fn_call = (ident + LPAREN + expr_list + RPAREN).setParseAction(insert_fn_argcount_tuple)
atom = ( (fn_call | string | integer) | pp.Group(LPAREN+expr+RPAREN)).addParseAction(push_first)
# atom = ( fn_call | pp.Group(LPAREN+expr+RPAREN)).addParseAction(push_first)
expr <<= atom 

bnf = pp.Forward()
bnf <<= tag_fn

funcs = """tag
value_equal
value_contain
value_match
value
"""


# functions
def tag(tag_name: str, value:Any)->Dict:
    if not tag_name or not value:
        return {}
    return {"tag_name": tag_name, "tag_value": value}

def test(*args, **kwargs):
    return ""

def value_equal(key: str, value, default=None, test=None):
    print(f"---{value_equal}---")
    print(f"key: {key}, value: {value}, defaul: {default}, test:{test}")
    return "value-1"

fns = {
    "tag": tag,
    "value_equal": value_equal,
    "test": test
}
exprStack = []

def evaluate_stack(s:List): # List param will be changed after invoke evaluate_stack function
    fn, arg_nums = s.pop(), 0
    if isinstance(fn, tuple):
        fn, arg_nums = fn
    if fn in fns:
        args = reversed([evaluate_stack(s) for _ in range(arg_nums)])
        return fns[fn](*args)
    else:
        return fn

test_str = """tag("tag_name_1", value_equal("proxy.province", "value", "return_value", test(1,2)))"""
# test_str = "123"
p = bnf.parse_string(test_str)
print(f"\nexprStack:{exprStack}\n")
t = evaluate_stack(exprStack)
print(f"tag:{t}")

上面代码的输出是:

('test', 2)
('value_equal', 4)
('tag', 2)

exprStack:['tag_name_1', 'proxy.province', 'value', 'return_value', '1', '2', ('test', 2), ('value_equal', 4)\]

我希望表达式栈包含标签功能。也许是这样的:

exprStack:['tag_name_1', 'proxy.province', 'value', 'return_value', '1', '2', ('test', 2), ('value_equal', 4), ('tag', 2)\]

【问题讨论】:

    标签: python python-3.x pyparsing


    【解决方案1】:

    你真的很接近。问题是,push_first 解析操作附加到原子,但 tag_fn 不是原子。所以它不会将其数据推送到 expr_stack。

    要解决此问题:

    1. 更改 atom 以包含 tag_fn,如下所示:

      atom = ((tag_fn | fn_call | string | integer) | pp.Group(LPAREN+expr+RPAREN)).addParseAction(push_first)
      
    2. 将 bnf 改为 expr 而不是 tag_fn:

      bnf <<= expr
      

      通过这两个更改,我得到了 expr_stack:

      exprStack:['tag_name_1', 'proxy.province', 'value', 'return_value', '1', '2', ('test', 2), ('value_equal', 4), ('tag', 2)]
      

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-03-13
      • 2014-07-03
      • 1970-01-01
      • 2021-07-12
      • 2010-10-05
      • 2013-10-19
      • 2020-05-16
      相关资源
      最近更新 更多