为了账号安全,请及时绑定邮箱和手机立即绑定

Pyparsing Precedence 打破一元运算符

Pyparsing Precedence 打破一元运算符

慕无忌1623718 2023-04-25 15:46:07
我正在尝试使用pyparsing. 我有以下代码实现我的解析器:variable_names = pyparsing.Combine(pyparsing.Literal('$') + pyparsing.Word(pyparsing.alphanums + '_'))integer = pyparsing.Word(pyparsing.nums)double = pyparsing.Combine(pyparsing.Word(pyparsing.nums) + '.' + pyparsing.Word(pyparsing.nums))parser = pyparsing.operatorPrecedence(variable_names | double | integer, [                                ('**', 2, pyparsing.opAssoc.RIGHT),                                ('-', 1, pyparsing.opAssoc.RIGHT),                                (pyparsing.oneOf('* / // %'), 2, pyparsing.opAssoc.LEFT),                                (pyparsing.oneOf('+ -'), 2, pyparsing.opAssoc.LEFT),                                (pyparsing.oneOf('> >= < <= == !='), 2, pyparsing.opAssoc.LEFT),                                ('not', 1, pyparsing.opAssoc.RIGHT),                                ('and', 2, pyparsing.opAssoc.LEFT),                                ('or', 2, pyparsing.opAssoc.LEFT)])在大多数情况下,这工作正常,但有时当我使用一元时它会中断-。具体来说,我认为(我可能是错的)如果我-在更高优先级的操作数之后使用它会中断,在这种情况下就是**. 以下示例显示了该问题:parsing 5 * 10 * -2             yields: ['5', '*', '10', '*', ['-', '2']]parsing 5 * 10 ** -2            yields: ['5', '*', '10']               # Wrongparsing 5 * 10 ** (-2)          yields: ['5', '*', ['10', '**', ['-', '2']]]parsing 5 and not 8             yields: ['5', 'and', ['not', '8']]parsing 5 and - 8               yields: ['5', 'and', ['-', '8']]发生这种情况有什么原因吗?我错过了什么?
查看完整描述

2 回答

?
米琪卡哇伊

TA贡献1998条经验 获得超6个赞

至于我,你应该定义-为更高**


('-', 1, pyparsing.opAssoc.RIGHT),

('**', 2, pyparsing.opAssoc.RIGHT),

这应该可以解决您的问题。


最小的工作代码


import pyparsing


variable_names = pyparsing.Combine(pyparsing.Literal('$') + pyparsing.Word(pyparsing.alphanums + '_'))


integer = pyparsing.Word(pyparsing.nums)


double = pyparsing.Combine(pyparsing.Word(pyparsing.nums) + '.' + pyparsing.Word(pyparsing.nums))


parser = pyparsing.operatorPrecedence(

            variable_names | double | integer,

            [

                ('-',  1, pyparsing.opAssoc.RIGHT),

                ('**', 2, pyparsing.opAssoc.RIGHT),

                (pyparsing.oneOf('* / // %'), 2, pyparsing.opAssoc.LEFT),

                (pyparsing.oneOf('+ -'), 2, pyparsing.opAssoc.LEFT),

                (pyparsing.oneOf('> >= < <= == !='), 2, pyparsing.opAssoc.LEFT),

                ('not', 1, pyparsing.opAssoc.RIGHT),

                ('and', 2, pyparsing.opAssoc.LEFT),

                ('or',  2, pyparsing.opAssoc.LEFT)

            ]

        )


examples = [

    "5 * 10 ** -2",

    "5 * 10 * -2",

    "5 * 10 ** (-2)",

    "5 * -10 ** 2",

    "5 * (-10) ** 2",    

    "5 and not 8",

    "5 and -8",

    "1 ** -2",

    "-1 ** 2",

]


longest = max(map(len, examples))


for ex in examples:

    result = parser.parseString(ex)

    print(f'{ex:{longest}}  <=>  {result}')

结果:


5 * 10 ** -2    <=>  [['5', '*', ['10', '**', ['-', '2']]]]

5 * 10 * -2     <=>  [['5', '*', '10', '*', ['-', '2']]]

5 * 10 ** (-2)  <=>  [['5', '*', ['10', '**', ['-', '2']]]]

5 * -10 ** 2    <=>  [['5', '*', [['-', '10'], '**', '2']]]

5 * (-10) ** 2  <=>  [['5', '*', [['-', '10'], '**', '2']]]

5 and not 8     <=>  [['5', 'and', ['not', '8']]]

5 and -8        <=>  [['5', 'and', ['-', '8']]]

1 ** -2         <=>  [['1', '**', ['-', '2']]]

-1 ** 2         <=>  [[['-', '1'], '**', '2']]

顺便说一句:为了比较:C 运算符优先级和Python - 运算符优先级

编辑:


我之前保留时可以得到-500( 5 * -10 ** 2)但我使用[[5, '*', ['-', [10, '**', 2]]]]**-


integer = pyparsing.pyparsing_common.signed_integer

import pyparsing


variable_names = pyparsing.Combine(pyparsing.Literal('$') + pyparsing.Word(pyparsing.alphanums + '_'))


#integer = pyparsing.Word(pyparsing.nums)

integer = pyparsing.pyparsing_common.signed_integer


double = pyparsing.Combine(pyparsing.Word(pyparsing.nums) + '.' + pyparsing.Word(pyparsing.nums))


parser = pyparsing.operatorPrecedence(

            variable_names | double | integer,

            [

                ('**', 2, pyparsing.opAssoc.RIGHT),

                ('-',  1, pyparsing.opAssoc.RIGHT),

                (pyparsing.oneOf('* / // %'), 2, pyparsing.opAssoc.LEFT),

                (pyparsing.oneOf('+ -'), 2, pyparsing.opAssoc.LEFT),

                (pyparsing.oneOf('> >= < <= == !='), 2, pyparsing.opAssoc.LEFT),

                ('not', 1, pyparsing.opAssoc.RIGHT),

                ('and', 2, pyparsing.opAssoc.LEFT),

                ('or',  2, pyparsing.opAssoc.LEFT)

            ]

        )


examples = [

    "5 * 10 ** -2",

    "5 * 10 * -2",

    "5 * 10 ** (-2)",

    "5 * -10 ** 2",

    "5 * (-10) ** 2",    

    "5 and not 8",

    "5 and -8",

    "1 ** -2",

    "-1 ** 2",

]


longest = max(map(len, examples))


for ex in examples:

    result = parser.parseString(ex)

    print(f'{ex:{longest}}  <=>  {result}')

结果:


5 * 10 ** -2    <=>  [[5, '*', [10, '**', -2]]]

5 * 10 * -2     <=>  [[5, '*', 10, '*', ['-', 2]]]

5 * 10 ** (-2)  <=>  [[5, '*', [10, '**', ['-', 2]]]]

5 * -10 ** 2    <=>  [[5, '*', ['-', [10, '**', 2]]]]

5 * (-10) ** 2  <=>  [[5, '*', [['-', 10], '**', 2]]]

5 and not 8     <=>  [[5, 'and', ['not', 8]]]

5 and -8        <=>  [[5, 'and', ['-', 8]]]

1 ** -2         <=>  [[1, '**', -2]]

-1 ** 2         <=>  [['-', [1, '**', 2]]]

Doc forpyparsing_common与其他预定义的表达式


查看完整回答
反对 回复 2023-04-25
?
翻阅古今

TA贡献1780条经验 获得超5个赞

很抱歉带回这么老的主题,但我正在为我的项目编写一个非常相似的解析器,它混合了布尔逻辑和数学运算符,我最终得到了一个看起来很合适的相似代码。


由于此处给出的解析器遇到与我相同的问题,因此我将使用它来说明我的问题。


我无法让它解析“$true == not $false”,基本上,如果没有括号,比较后的任何“not”都不会起作用。


$true == $false        <=>  [['$true', '==', '$false']]

$true == not $false    <=>  ['$true']

$true == (not $false)  <=>  [['$true', '==', ['not', '$false']]]

如您所见,没有“not”或有括号,它解析得很好,但是有一个简单的“not”,它似乎忽略了“==”之后的所有内容


在 infix_notation(以前的 operatorPrecedence)中先移动“not”运算符是什么修复方法。然后我得到了这些结果:


$true == not $false    <=>  [['$true', '==', ['not', '$false']]]

$true == (not $false)  <=>  [['$true', '==', ['not', '$false']]]

这是伟大的,但当然它打破了诸如“$true and not 10 == 9”之类的运算符优先级,我想像在 python 中那样解析“$true and not (10 == 9)”而不是解析像那样:


$true and not 10 == 9  <=>  [['$true', 'and', [['not', 10], '==', 9]]]

我想知道您是否在解析器的实现中遇到过这些用例并找到了解决方法。


查看完整回答
反对 回复 2023-04-25
  • 2 回答
  • 0 关注
  • 89 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信