pyparsing infixNotation优化

时间:2017-04-06 02:54:23

标签: python pyparsing infix-notation

infixNotation的实施速度比使用enablePackrat时的运行速度慢,这大大提高了性能。

解析需要识别和解析以下类型的字符串:

  • 基本算术运算,数字,否定和括号分组
  • 格式prefix::dotted.alphanum.string -> [prefix::dotted.alphanum.string]
  • 的分组
  • 看起来像函数调用的字符串,例如pow(some::var + 2.3, 5) -> [pow, [[some::var, +, 2.3], 5]]

我使用的代码:

def parse_expression(expr_str):

    fraction = Combine("." + Word(nums))
    number = Combine(Word(nums) + Optional(fraction)).setParseAction(str_to_num)

    event_id_expr = Word(alphanums + "_") + "::"
    dotted_columns = Combine(Word(alphanums + "_") + Optional("."))

    column_expr = Combine(event_id_expr + OneOrMore(dotted_columns))

    arith_expr = infixNotation(column_expr | number, [
        (Word(alphanums + "_"), 1, opAssoc.RIGHT),
        ("-", 1, opAssoc.RIGHT),
        (oneOf("* /"), 2, opAssoc.LEFT),
        (oneOf("+ -"), 2, opAssoc.LEFT),
        (Literal(","), 2, opAssoc.LEFT)
    ])

    parsed_expr = arith_expr.parseString(expr_str).asList()[0]

    return parsed_expr

 def str_to_num(t):
      num_str = t[0]
      try:
          return int(num_str)
      except ValueError:
          return float(num_str)

我能做出哪些改变会导致显着的性能提升?我解析的结构相当简单,但它们分批进行。平均每个字符串大约需要5.3毫秒。

1 个答案:

答案 0 :(得分:2)

看起来你是"捏造"函数好像是运算符,我认为你最好将函数调用移动到infixNotation的操作数表达式中:

def parse_expression(expr_str):

    number = pyparsing_common.number()

    event_id_expr = Word(alphas+"_", alphanums + "_") + "::"
    dotted_columns = Combine(Word(alphas+"_", alphanums + "_") + Optional("."))

    column_expr = Combine(event_id_expr + OneOrMore(dotted_columns))

    func_name = Word(alphas+"_", alphanums+'_')
    LPAR, RPAR = map(Suppress, "()")
    arith_expr = Forward()
    func_call = Group(func_name('name') 
                      + LPAR 
                      + Group(Optional(delimitedList(arith_expr)))("args") 
                      + RPAR)

    arith_expr <<= infixNotation(number | func_call | column_expr, [
        ("-", 1, opAssoc.RIGHT),
        (oneOf("* /"), 2, opAssoc.LEFT),
        (oneOf("+ -"), 2, opAssoc.LEFT),
    ])

    parsed_expr = arith_expr.parseString(expr_str)[0]

    return parsed_expr

我还修改了大部分标识符以使用Word的双参数形式 - 只需使用Word(alphanums+"_")也可以匹配普通整数,我不会认为是你的意图。如果我弄错了,那就把它们放回原处。