Skip to main content
 首页 » 编程设计

Python递归函数或循环将字符串转换为json逻辑对象

2025年05月04日27freeliver54

我有这个功能:

def req_splitter(req_string): 
    req = {} 
    if " AND " in req_string: 
        cond = "AND" 
        req_splitted = req_string.split(" AND ") 
    elif " OR " in req_string: 
        cond = "OR" 
        req_splitted = req_string.split(" OR ") 
    else: 
        cond = "AND" 
        req_splitted = [req_string] 
 
    if len(req_splitted) > 1: 
        for sub_req in req_splitted: 
            sub_req_splitted = req_splitter(sub_req) 
            req[cond] = list()#new_req 
            req[cond].append(sub_req_splitted) 
    else: 
        req[cond] = req_splitted 
    return req 

它旨在将像这样的字符串转换为 json 逻辑条件:

Barracks AND Tech Lab 
Lair OR Hive 
Hatchery OR Lair OR Hive 
Cybernetics Core AND Gateway OR Warpgate 
Forge AND Twilight Council AND Ground Armor 1 
Spire OR Greater Spire AND Hive AND Flyer Flyer Carapace 2 
Spire OR Greater Spire AND Lair OR Hive AND Flyer Attacks 1 

json_logic 条件是这样的:

{ 
    "and": [ 
            { 
            "or": [ 
                "Gateway", 
                "Warpgate" 
            ] 
        }, 
        "Cybernetics Core" 
    ] 
} 

我的递归函数应该如何帮助我将字符串拆分为条件对象,如上例所示?


为了帮助您理解问题:

json_logic是一个检查条件的模块,就像您在上面看到的字典一样,并根据您比较的内容返回一些结果。

条件如何运作: key-value par 是一个单一的逻辑语句。 键代表逻辑条件。 列表中的值代表操作数。 如果值本身不是列表而是字典,它会递归。

你可以把它比作“polish notation”

最后一件事 - AND 语句比 OR 语句具有更高的优先级,并且 OR 语句总是在一起。

请您参考如下方法:

您需要编写一个简单的自上而下的解析器。无与伦比的 effbot 写了一个 great tutorial关于那种事情。

标记化只是在 r'\s+(OR|AND)\s+' 正则表达式上拆分,然后将 OR 和 AND 识别为运算符,其余为文字。 AND 和 OR 标记 .led() 方法可以展平相同类型的直接嵌套运算符。

我已经使用更多的 OOP(而不是全局变量)实现了那里描述的内容,并使其与 Python 2 和 3 兼容:

import re 
from functools import partial 
 
 
class OpAndToken(object): 
    lbp = 10 
    op = 'and' 
    def led(self, parser, left): 
        right = parser.expression(self.lbp) 
        operands = [] 
        for operand in left, right: 
            # flatten out nested operands of the same type 
            if isinstance(operand, dict) and self.op in operand: 
                operands.extend(operand[self.op]) 
            else: 
                operands.append(operand) 
        return {self.op: operands} 
 
 
class OpOrToken(OpAndToken): 
    lbp = 20 
    op = 'or' 
 
 
class LiteralToken(object): 
    def __init__(self, value): 
        self.value = value 
    def nud(self): 
        return self.value 
 
 
class EndToken(object): 
    lbp = 0 
 
 
class Parser(object): 
    operators = {'AND': OpAndToken, 'OR': OpOrToken} 
    token_pat = re.compile("\s+(AND|OR)\s+") 
 
    def __init__(self, program): 
        self.program = program 
        self.tokens = self.tokenizer() 
        self.token = next(self.tokens) 
 
    def expression(self, rbp=0): 
        t = self.token 
        self.token = next(self.tokens) 
        left = t.nud() 
        while rbp < self.token.lbp: 
            t = self.token 
            self.token = next(self.tokens) 
            left = t.led(self, left) 
        return left 
 
    def tokenizer(self): 
        for tok in self.token_pat.split(self.program): 
            if tok in self.operators: 
                yield self.operators[tok]() 
            else: 
                yield LiteralToken(tok) 
        yield EndToken() 
 
    def parse(self): 
        return self.expression() 

这会将您的格式解析为预期的输出:

>>> Parser('foo AND bar OR spam AND eggs').parse() 
{'and': ['foo', {'or': ['bar', 'spam']}, 'eggs']} 

在您的输入行上演示:

>>> from pprint import pprint 
>>> tests = '''\ 
... Barracks AND Tech Lab 
... Lair OR Hive 
... Hatchery OR Lair OR Hive 
... Cybernetics Core AND Gateway OR Warpgate 
... Forge AND Twilight Council AND Ground Armor 1 
... Spire OR Greater Spire AND Hive AND Flyer Flyer Carapace 2 
... Spire OR Greater Spire AND Lair OR Hive AND Flyer Attacks 1 
... '''.splitlines() 
>>> for test in tests: 
...     pprint(Parser(test).parse()) 
... 
{'and': ['Barracks', 'Tech Lab']} 
{'or': ['Lair', 'Hive']} 
{'or': ['Hatchery', 'Lair', 'Hive']} 
{'and': ['Cybernetics Core', {'or': ['Gateway', 'Warpgate']}]} 
{'and': ['Forge', 'Twilight Council', 'Ground Armor 1']} 
{'and': [{'or': ['Spire', 'Greater Spire']}, 'Hive', 'Flyer Flyer Carapace 2']} 
{'and': [{'or': ['Spire', 'Greater Spire']}, 
         {'or': ['Lair', 'Hive']}, 
         'Flyer Attacks 1']} 

请注意,对于一行中的多个 OR 或 AND 运算符,操作数是组合在一起的。

我将把对 (...) 括号的支持留给读者;本教程向您展示了如何执行此操作(只需将 advance() 函数作为 Parser 类上的一个方法并将解析器传递给 .nud() 也调用,或者在创建 token 类实例时传入解析器)。