python - pyparsing如何使用infixNotation来表示iif(cond, if true, if false)

标签 python python-3.x pyparsing

我需要使用pyparsing来解析它:iif(condition,value if true,value if false),但是这种三元比较应该有另一个比较,我的意思是:

`iif(iif(condition1,value1,value2)>iif(condition2,value1,value2),value3,value4)`

我发现了这个:

integer = Word(nums)
variable = Word(alphas, alphanums)
boolLiteral = oneOf("true false")
operand = boolLiteral | variable | integer
comparison_op = oneOf("== <= >= != < >")
QM,COLON = map(Literal,"?:")
expr = infixNotation(operand,
    [
    (comparison_op, 2, opAssoc.LEFT),
    ((QM,COLON), 3, opAssoc.LEFT),
    ])

它能够解析这个: expr.parseString("(x==1? true: (y == 10? 100 : 200) )")

但我无法修改此代码以满足我的需要。我怎样才能实现这个目标?

更新

感谢 Paul 先生,我想出了这个解决方案:

arith_expr = Forward()

iif = CaselessKeyword("iif")
    open = Literal("(")
    close = Literal(")")

    var_name = pyparsing_common.identifier()
    fn_call = Group(iif + open - Group(Optional(delimitedList(arith_expr))) + close)
    arith_operand = fn_call | num

    rel_comparison_operator = oneOf("< > <= >=")
    eq_comparison_operator = oneOf("== !=")
    plus_minus_operator = oneOf("+ -")
    mult_div_operator = oneOf("* / %")

    arith_expr <<= infixNotation(arith_operand,
                                    [
                                        # add other operators here - in descending order of precedence
                                        # http://www.tutorialspoint.com/cprogramming/c_operators_precedence.htm
                                        ('-', 1, opAssoc.RIGHT),
                                        (mult_div_operator, 2, opAssoc.LEFT,),
                                        (plus_minus_operator, 2, opAssoc.LEFT,),
                                        (rel_comparison_operator, 2, opAssoc.LEFT,),
                                        (eq_comparison_operator, 2, opAssoc.LEFT,),
                                    ]
                                    )

我正在使用我以前的一些规则。现在我投票结束这篇文章。

最佳答案

正如 @sepp2k 在他的评论中提到的,您尝试解析的字符串不是中缀表示法,尽管您最终可能会用作中缀表示法的操作数。并且传递给 iif 的参数本身可能是中缀表示法表达式。因此中缀表示法肯定会成为该解析器的一部分,但它不会是解析您的 iif 函数调用的部分。

这是函数调用在 pyparsing 中的样子:

fn_call = pp.Group(var_name + LPAREN - pp.Group(pp.Optional(pp.delimitedList(arith_expr))) + RPAREN)

用于定义算术表达式的操作数本身可以包含函数调用,因此解析器的递归将要求您使用 pyparsing 的 Forward 类。

arith_expr = pp.Forward()

这将允许您在完全定义 arith_expr 的外观之前在其他子表达式中使用 arith_expr(就像我们刚刚在 fn_call 中所做的那样)。

言归正传,这是一个用于解析 iif 函数的最小解析器:

import pyparsing as pp

# for recursive infix notations, or those with many precedence levels, it is best to enable packrat parsing
pp.ParserElement.enablePackrat()
LPAREN, RPAREN = map(pp.Suppress, "()")

arith_expr= pp.Forward()

var_name = pp.pyparsing_common.identifier()
integer = pp.pyparsing_common.integer()
fn_call = pp.Group(var_name + LPAREN - pp.Group(pp.Optional(pp.delimitedList(arith_expr))) + RPAREN)
arith_operand = fn_call | var_name | integer

rel_comparison_operator = pp.oneOf("< > <= >=")
eq_comparison_operator = pp.oneOf("== !=")
plus_minus_operator = pp.oneOf("+ -")
mult_div_operator = pp.oneOf("* / %")

arith_expr <<= pp.infixNotation(arith_operand,
                                [
                                    # add other operators here - in descending order of precedence
                                    # http://www.tutorialspoint.com/cprogramming/c_operators_precedence.htm
                                    (mult_div_operator, 2, pp.opAssoc.LEFT,),
                                    (plus_minus_operator, 2, pp.opAssoc.LEFT,),
                                    (rel_comparison_operator, 2, pp.opAssoc.LEFT,),
                                    (eq_comparison_operator, 2, pp.opAssoc.LEFT,),
                                ]
                                )

使用 runTests,我们可以针对一些测试用例进行尝试:

tests = """\
    cos(60)
    sqrt(1 - sin(60) * sin(60))
    divmod(a, 100)
    iif(iif(condition1,value1,value2)>iif(condition2,value1,value2),value3,value4)
    """
arith_expr.runTests(tests)

打印:

cos(60)
[['cos', [60]]]
[0]:
  ['cos', [60]]
  [0]:
    cos
  [1]:
    [60]


sqrt(1 - sin(60) * sin(60))
[['sqrt', [[1, '-', [['sin', [60]], '*', ['sin', [60]]]]]]]
[0]:
  ['sqrt', [[1, '-', [['sin', [60]], '*', ['sin', [60]]]]]]
  [0]:
    sqrt
  [1]:
    [[1, '-', [['sin', [60]], '*', ['sin', [60]]]]]
    [0]:
      [1, '-', [['sin', [60]], '*', ['sin', [60]]]]
      [0]:
        1
      [1]:
        -
      [2]:
        [['sin', [60]], '*', ['sin', [60]]]
        [0]:
          ['sin', [60]]
          [0]:
            sin
          [1]:
            [60]
        [1]:
          *
        [2]:
          ['sin', [60]]
          [0]:
            sin
          [1]:
            [60]


divmod(a, 100)
[['divmod', ['a', 100]]]
[0]:
  ['divmod', ['a', 100]]
  [0]:
    divmod
  [1]:
    ['a', 100]


iif(iif(condition1,value1,value2)>iif(condition2,value1,value2),value3,value4)
[['iif', [[['iif', ['condition1', 'value1', 'value2']], '>', ['iif', ['condition2', 'value1', 'value2']]], 'value3', 'value4']]]
[0]:
  ['iif', [[['iif', ['condition1', 'value1', 'value2']], '>', ['iif', ['condition2', 'value1', 'value2']]], 'value3', 'value4']]
  [0]:
    iif
  [1]:
    [[['iif', ['condition1', 'value1', 'value2']], '>', ['iif', ['condition2', 'value1', 'value2']]], 'value3', 'value4']
    [0]:
      [['iif', ['condition1', 'value1', 'value2']], '>', ['iif', ['condition2', 'value1', 'value2']]]
      [0]:
        ['iif', ['condition1', 'value1', 'value2']]
        [0]:
          iif
        [1]:
          ['condition1', 'value1', 'value2']
      [1]:
        >
      [2]:
        ['iif', ['condition2', 'value1', 'value2']]
        [0]:
          iif
        [1]:
          ['condition2', 'value1', 'value2']
    [1]:
      value3
    [2]:
      value4

关于python - pyparsing如何使用infixNotation来表示iif(cond, if true, if false),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56408430/

相关文章:

python - 当表单未提交时,如何使用django中的get方法处理表单元素

python - 如何删除空数据行

python - 文件 "<string>"第 1 行,在 <module> 中 NameError : name ' ' is not defined in ATOM

python - PyParsing 的 searchString 与 StringStart() 和 StringEnd()

python - pyparse : How to handle "{ foo bar\n }" formatted stream?

python - 获取导入模块代码的路径

python - Numpy:将矩阵与 3d 张量相乘——建议

Python 3 - ValueError : Found array with 0 sample(s) (shape=(0, 11)) 而 MinMaxScaler 要求至少为 1

python - 提取字典中的值

python - 构建一个简单的解析器,能够使用 PyParse 解析不同的日期格式