【问题标题】:Parse boolean arithmetic including parentheses with regex?用正则表达式解析布尔算术,包括括号?
【发布时间】:2011-01-08 06:18:59
【问题描述】:

是否有一个正则表达式可以解析表示简单布尔算术的字符串(在 Python 和/或 Javascript 中,不需要是相同的表达式)?比如我要解析这个字符串:

a and (b and c) and d or e and (f or g)

假设:
* 括号不嵌套
* a, b, ..., z 不是子表达式

生成的捕获应首先按括号分组,然后我使用相同或更简单的正则表达式再次对其进行解析。

我已经成功编写了一个简单的正则表达式来解析没有括号的布尔算术。

有什么想法吗?

【问题讨论】:

  • 你到底想做什么?
  • 我有一个自定义的客户端 JS 实现,它产生这样一个布尔算术表达式(其中 a、b、c ......实际上是字段查找,供以后在 Django ORM 过滤器中使用)然后发布到服务器并用 Python 解析。我希望这是有道理的。
  • 所以您想解析该表达式以便稍后对其进行评估,对吧?
  • 不确定您所说的“评估”是什么意思。在这一点上,我不太关心实际术语,因为我已经有了一个不错的实现来识别 a、b、...、z 中的标记。

标签: javascript python regex


【解决方案1】:

通常您会为此任务使用例如 recursive descent parser,但您可以使用正则表达式获取所有部分(令牌):

x = 'a and (b and c) and d or e and (f or g)'
import re

matches = re.findall(r'\(.*?\)|\w+', x)
print ','.join(matches)

运营商通常有不同的precedence。首先计算括号,然后是 and 表达式,最后是 or 表达式,在同等优先级的情况下按从左到右的顺序。你说你想首先返回括号匹配,但实际上你通常会使用这些部分构建一个表达式树并递归地对其进行评估。

【讨论】:

  • +1,请注意,如果括号确实嵌套,则需要采取完全不同的方法,因为正则表达式无法处理计数(即嵌套任何内容)
  • 马克,您指出涉及表达式树的“正确”解决方案是正确的,但鉴于括号从未嵌套在我的实现中,我认为单个正则表达式可能就足够了。
【解决方案2】:

假设没有嵌套将其简化为可以使用正则表达式的级别。匹配的正则表达式(假设和/或仅可以轻松扩展):

>>> expr = 'a and (b and c) and d or e and (f or g)'
>>> regex = re.compile('\((\w+)\s+(and|or)\s+(\w)\)|(\w+)')
>>> results = regex.findall(expr)
>>> results = [i[:3] if i[0] else i[3] for i in results]
>>> results
['a', 'and', ('b', 'and', 'c'), 'and', 'd', 'or', 'e', 'and', ('f', 'or', 'g')]

现在您将括号部分作为 3 个字符串的元组(操作数-运算符-操作数),将字符串的其余部分作为每个标记(运算符或操作数)的字符串。

您可以遍历列表,计算每个带括号的表达式,然后用结果替换它。完成后,您可以再次遍历它并从左到右或根据您设置的一些优先规则进行评估(例如,仅继续评估 AND,直到用完 AND,然后开始评估 OR)。

【讨论】:

    【解决方案3】:

    pyparsing wiki 上的 Examples page 包含一个示例 SimpleBool.py,它将解析和评估表达式,例如:

    test = ["p and not q",
            "not not p",
            "not(p and q)",
            "q or not p and r",
            "q or not (p and r)",
            "p or q or r",
            "p or q or r and False",
            ]
    

    (嗯,没有任何嵌套括号的示例,但这些 也受支持。)

    实际的解析器是使用以下代码完整定义的:

    boolOperand = Word(alphas,max=1) | oneOf("True False")
    boolExpr = operatorPrecedence( boolOperand,
        [
        ("not", 1, opAssoc.RIGHT, BoolNot),
        ("and", 2, opAssoc.LEFT,  BoolAnd),
        ("or",  2, opAssoc.LEFT,  BoolOr),
        ])
    

    示例的其余部分给出了 BoolNot、BoolOr 和 BoolAnd 的实现。 operatorPrecedence 构造定义了操作序列、它们的数量和关联性,以及可选的要使用解析的元素构造的类。 operatorPrecedence 然后负责定义语法,包括在嵌套括号内递归定义 boolExpr。生成的结构类似于使用给定 BoolXxx 类的嵌套 AST。这些类依次定义eval 方法,以便可以使用以下代码解析和评估表达式:

    p = True
    q = False
    r = True
    for t in test:
        res = boolExpr.parseString(t)[0]
        print t,'\n', res, '=', bool(res),'\n'
    

    pyparsing 本身是一个有点长的模块,但它是一个单一的源文件,因此它的安装占用空间非常小。 MIT 许可证允许非商业和商业用途。

    【讨论】:

    • 谢谢,保罗,这看起来很简单,我会看看!
    猜你喜欢
    • 1970-01-01
    • 2011-09-05
    • 1970-01-01
    • 1970-01-01
    • 2014-11-27
    • 2015-12-30
    • 1970-01-01
    • 1970-01-01
    • 2013-01-26
    相关资源
    最近更新 更多