Python 将字符串转换为 json 逻辑对象的递归函数或循环
Python recursive function or cycle to convert string to json logical object
我有这个功能:
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 是一个检查条件的模块,就像你在上面看到的字典和 returns 一些结果,取决于你比较的内容。
条件如何运作:
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
运算符,操作数会合并。
我将在 reader 中添加对 (...)
括号的支持;本教程向您展示了如何执行此操作(只需将 advance()
函数作为 Parser
class 上的一个方法并将解析器也传递给 .nud()
调用,或者传递创建令牌 class 个实例时的解析器)。
我有这个功能:
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 是一个检查条件的模块,就像你在上面看到的字典和 returns 一些结果,取决于你比较的内容。
条件如何运作: 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
运算符,操作数会合并。
我将在 reader 中添加对 (...)
括号的支持;本教程向您展示了如何执行此操作(只需将 advance()
函数作为 Parser
class 上的一个方法并将解析器也传递给 .nud()
调用,或者传递创建令牌 class 个实例时的解析器)。