pyparsing infixNotation优化
pyparsing infixNotation optimization
即使在使用 enablePackrat
之后,我对 infixNotation
的实现比我希望的要慢 运行,这大大提高了性能。
解析需要识别并解析以下类型的字符串:
- 基本算术运算、数字、否定和括号分组
- 格式为
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.3ms。
看起来你是 "fudging" 函数,就好像它们是运算符一样,我认为你最好将函数调用移动到 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+"_")
也将匹配普通整数,我不认为 是你的意图。如果我弄错了,就把它们放回原来的样子。
即使在使用 enablePackrat
之后,我对 infixNotation
的实现比我希望的要慢 运行,这大大提高了性能。
解析需要识别并解析以下类型的字符串:
- 基本算术运算、数字、否定和括号分组
- 格式为
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.3ms。
看起来你是 "fudging" 函数,就好像它们是运算符一样,我认为你最好将函数调用移动到 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+"_")
也将匹配普通整数,我不认为 是你的意图。如果我弄错了,就把它们放回原来的样子。