前言
Python 3.11
pyparsing 3.1.2
案例
# encoding: utf-8
# author: qbit
# date: 2024-04-23
# summary: 化简括号冗余的与或非逻辑表达式
import pyparsing as pp
line = '(((owner=111 AND doc_type=222))) OR author=333 OR organ=444 AND ((NOT pub_year>555))'
operator = (
pp.Literal(r'=') | # 全等精确匹配
pp.Literal(r'>') # 前后模糊匹配
)
field = pp.Word(pp.alphanums + '_')
value = pp.Word(pp.alphanums)
exprGroup: pp.Group = pp.Group(field("field") + operator("operator") + value("value"))
logicAND = pp.Word('AND')('logic')
logicOR = pp.Word('OR')('logic')
logicNOT = pp.Word('NOT')('logic')
exprForward = pp.infixNotation(
exprGroup("Expr"),
[
(logicAND, 2, pp.opAssoc.LEFT, ),
(logicOR, 2, pp.opAssoc.LEFT, ),
(logicNOT, 1, pp.opAssoc.RIGHT, ),
]
).setResultsName("Result", True)
result: pp.results.ParseResults = exprForward.parseString(line, parseAll=True)
def list2qs(lst):
r''' 将 pyparsing 解析出来的列表递归转化为 Elasticsearch query_string '''
if (len(lst) == 1) and isinstance(lst[0], list): # 列表中只有一个列表元素
return list2qs(lst[0])
if lst[0] == 'NOT':
return f"(NOT {list2qs(lst[1])})"
if lst[1] == 'AND':
return ' AND '.join( [list2qs(x) for x in lst[0::2]]) # 步长为2取数据
if lst[1] == 'OR':
return ' OR '.join( [list2qs(x) for x in lst[0::2]]) # 步长为2取数据
match lst[1]:
case r'=':
return f"{lst[0]}={lst[2]}"
case r'>':
return f"{lst[0]}>{lst[2]}"
case _:
pass
qs = list2qs(result.as_list())
print(f"冗余表达式: {line}")
print(f"简化表达式: {qs}")
冗余表达式: (((owner=111 AND doc_type=222))) OR author=333 OR organ=444 AND ((NOT pub_year>555))
简化表达式: owner=111 AND doc_type=222 OR author=333 OR organ=444 AND (NOT pub_year>555)
相关资料
库
文章
本文出自 qbit snap
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。