如何执行存储为字符串的布尔逻辑,最好不使用 eval()?
How to execute a boolean logic stored as a string, preferably without eval()?
我有以下 YAML 文件,包含匹配文件名的解析逻辑:
rules_container = """
file_name:
rule_1: {module: str, method: startswith, args: [s_]}
rule_2: {module: str, method: endswith, args: [.log]}
logic: rule_1 and rule_2
"""
我加载它并得到以下映射:
>>> import yaml
>>> import pprint
>>> d_yml = yaml.safe_load(rules_container)
>>> pprint.pprint(d_yml)
{'file_name': {'logic': 'rule_1 and rule_2',
'rule_1': {'args': ['s_'],
'method': 'startswith',
'module': 'str'},
'rule_2': {'args': ['.log'],
'method': 'endswith',
'module': 'str'}}}
下面的函数帮我解析了上面的规则,最终得到:
- 编译规则字典
- 将规则应用于字符串(即文件名)的逻辑
def rule_compiler(module, method, args=None, kwargs=None):
def str_parser(string):
return getattr(string, method)(*args)
return str_parser
def rule_parser(container):
compiled_rules = {
k:rule_compiler(**v) for k,v in container.items() if k.startswith('rule')
}
logic = container.get('logic', None)
return compiled_rules, logic
注意:我在这里没有使用 module
和 kwargs
,但它们在配置文件的其他地方用于其他规则。
所以,如果我在规则的容器上调用 rule_parser()
,我会得到:
>>> rp = rule_parser(d_yml['file_name'])
>>> print(rp)
({'rule_1': <function __main__.rule_compiler.<locals>.str_parser(string)>,
'rule_2': <function __main__.rule_compiler.<locals>.str_parser(string)>},
'rule_1 and rule_2')
如果我尝试使用每条规则解析字符串,它们会按预期工作:
>>> fname = 's_test.out'
>>> rp[0]['rule_1'](fname)
True
>>> rp[0]['rule_2'](fname)
False
我想应用“逻辑”定义的逻辑并得到这个:
>>> rp[0]['rule_1'](fname) and rp[0]['rule_2'](fname)
False
我已经想到了一种方法,通过解析包含布尔逻辑的字符串,将其转换为与上述类似的内容,然后对其调用 eval()
。
你能想到不涉及eval()
的其他方法吗?
注意:可能有两个以上的规则,因此用简单的“and/or”替换逻辑,然后使用某种 if
语句来确定应用哪一个不会要么工作。
注意:在这种特定情况下,使用正则表达式并完全消除对多个规则的需求不是一种选择。
谢谢!
这是一个想法,使用 pandas.eval
,不确定它是否适合你的情况。
import pandas as pd
fname = 's_test.out'
rule, logic = rp
def apply_rule(rule_dict: dict, fname: str) -> dict:
return {rule: func(fname)
for rule, func in rule_dict.items()}
print(pd.eval(logic, local_dict = apply_rule(rule, fname)))
输出:
False
正确的答案可以跨越任何地方,从使用像 boolean.py to parse your strings (less flexible, probably easiest choice other than eval
) to reading up on lexers and parsers 这样的库并从头开始实施,或者使用解析器生成软件(最灵活,但困难且耗时)。在这种情况下,我可能会建议从专门为评估布尔表达式而构建的库开始,如果这不起作用,请尝试更复杂的东西。
编辑:我应该注意,如果没有用户注入恶意代码的入口点,您可以可以使用eval
,您可以正确清理 eval 字符串等.- 可能不值得你花时间,但如果其他选项不适合你的需要,则值得考虑。
我有以下 YAML 文件,包含匹配文件名的解析逻辑:
rules_container = """
file_name:
rule_1: {module: str, method: startswith, args: [s_]}
rule_2: {module: str, method: endswith, args: [.log]}
logic: rule_1 and rule_2
"""
我加载它并得到以下映射:
>>> import yaml
>>> import pprint
>>> d_yml = yaml.safe_load(rules_container)
>>> pprint.pprint(d_yml)
{'file_name': {'logic': 'rule_1 and rule_2',
'rule_1': {'args': ['s_'],
'method': 'startswith',
'module': 'str'},
'rule_2': {'args': ['.log'],
'method': 'endswith',
'module': 'str'}}}
下面的函数帮我解析了上面的规则,最终得到:
- 编译规则字典
- 将规则应用于字符串(即文件名)的逻辑
def rule_compiler(module, method, args=None, kwargs=None):
def str_parser(string):
return getattr(string, method)(*args)
return str_parser
def rule_parser(container):
compiled_rules = {
k:rule_compiler(**v) for k,v in container.items() if k.startswith('rule')
}
logic = container.get('logic', None)
return compiled_rules, logic
注意:我在这里没有使用 module
和 kwargs
,但它们在配置文件的其他地方用于其他规则。
所以,如果我在规则的容器上调用 rule_parser()
,我会得到:
>>> rp = rule_parser(d_yml['file_name'])
>>> print(rp)
({'rule_1': <function __main__.rule_compiler.<locals>.str_parser(string)>,
'rule_2': <function __main__.rule_compiler.<locals>.str_parser(string)>},
'rule_1 and rule_2')
如果我尝试使用每条规则解析字符串,它们会按预期工作:
>>> fname = 's_test.out'
>>> rp[0]['rule_1'](fname)
True
>>> rp[0]['rule_2'](fname)
False
我想应用“逻辑”定义的逻辑并得到这个:
>>> rp[0]['rule_1'](fname) and rp[0]['rule_2'](fname)
False
我已经想到了一种方法,通过解析包含布尔逻辑的字符串,将其转换为与上述类似的内容,然后对其调用 eval()
。
你能想到不涉及eval()
的其他方法吗?
注意:可能有两个以上的规则,因此用简单的“and/or”替换逻辑,然后使用某种 if
语句来确定应用哪一个不会要么工作。
注意:在这种特定情况下,使用正则表达式并完全消除对多个规则的需求不是一种选择。
谢谢!
这是一个想法,使用 pandas.eval
,不确定它是否适合你的情况。
import pandas as pd
fname = 's_test.out'
rule, logic = rp
def apply_rule(rule_dict: dict, fname: str) -> dict:
return {rule: func(fname)
for rule, func in rule_dict.items()}
print(pd.eval(logic, local_dict = apply_rule(rule, fname)))
输出:
False
正确的答案可以跨越任何地方,从使用像 boolean.py to parse your strings (less flexible, probably easiest choice other than eval
) to reading up on lexers and parsers 这样的库并从头开始实施,或者使用解析器生成软件(最灵活,但困难且耗时)。在这种情况下,我可能会建议从专门为评估布尔表达式而构建的库开始,如果这不起作用,请尝试更复杂的东西。
编辑:我应该注意,如果没有用户注入恶意代码的入口点,您可以可以使用eval
,您可以正确清理 eval 字符串等.- 可能不值得你花时间,但如果其他选项不适合你的需要,则值得考虑。