在Python中处理嵌套的布尔查询字符串

时间:2017-05-10 00:01:36

标签: python regex parsing nlp booleanquery

我有像这样的字符串布尔查询

   queryString= """And(
                      OR(abc,xyz,wxy),
                      AND(AND(xyz,wxy),xzy),
                      XOR(x1,y1, AND(xy,zz))  
                      )"""

目前我很难修改上面的查询字符串,因为我想

  1. 在上一个OR(x3,y3)
  2. 中添加另一个XOR
  3. 删除整个OR(abc,xyz,wxy)
  4. 具有所需的输出

       resultQueryString= """And(                        
                                AND(AND(xyz,wxy),xzy),
                                XOR(x1,y1, AND(xy,zz),OR(x3,y3))  
                                )"""
    

    我认为除非我为每个不同的查询提出复杂的正则表达式,否则我不能轻易做到。

    我正在尝试编写一个python函数,它将上面的字符串布尔查询作为输入并输出树数据结构。

    这样我就可以遍历树并评估或更改我想要更改的查询部分。

    在上面的示例中,如果我将其作为树,我可以很容易地看到根是AND并遍历/修改其他分支等。

1 个答案:

答案 0 :(得分:1)

ast.parse函数似乎几乎完全符合您的要求:

ast.dump(ast.parse("""And(                        
                        AND(AND(xyz,wxy),xzy),
                        XOR(x1,y1, AND(xy,zz),OR(x3,y3))  
                        )""").body[0].value)
  

Call(func=Name(id='And', ctx=Load()), args=[Call(func=Name(id='AND', ctx=Load()), args=[Call(func=Name(id='AND', ctx=Load()), args=[Name(id='xyz', ctx=Load()), Name(id='wxy', ctx=Load())], keywords=[], starargs=None, kwargs=None), Name(id='xzy', ctx=Load())], keywords=[], starargs=None, kwargs=None), Call(func=Name(id='XOR', ctx=Load()), args=[Name(id='x1', ctx=Load()), Name(id='y1', ctx=Load()), Call(func=Name(id='AND', ctx=Load()), args=[Name(id='xy', ctx=Load()), Name(id='zz', ctx=Load())], keywords=[], starargs=None, kwargs=None), Call(func=Name(id='OR', ctx=Load()), args=[Name(id='x3', ctx=Load()), Name(id='y3', ctx=Load())], keywords=[], starargs=None, kwargs=None)], keywords=[], starargs=None, kwargs=None)], keywords=[], starargs=None, kwargs=None)

.body[0].value删除了两个无意义的抽象层,.dump仅用于输出。

以下是您在输出中执行转换的代码:

class Filterer(ast.NodeTransformer):
    def visit_Call(self, node):
            name=node.func.id
            if name == "OR" and len(node.args) == 3:
                    return None
            elif name == "XOR":
                    args = [ast.Name("x3",ast.Load()),
                            ast.Name("y3",ast.Load())]
                    func = ast.Name("OR",ast.Load())
                    node.args.append(ast.Call(func, args, [], None, None))
            return self.generic_visit(node)

以下是以格式打印结果的代码,但空格除外:( Python在ast模块中没有内置内容):

class Printer(ast.NodeVisitor):
    def visit_Call(self, node):
            self.visit(node.func)
            print("(",end="")
            comma = False
            for arg in node.args:
                    if comma:
                            print(",",end="")
                    comma=True
                    self.visit(arg)
            print(")",end="")
    def visit_Name(self, node):
            print(node.id,end="")

因此,最终的代码是:

Printer().visit(Filterer().visit(ast.parse(queryString)))