我正在创建一个程序,我需要创建一个逻辑来处理 eval() 函数的用户输入。 输入将是一个数学函数,我想处理一些异常情况并确保该字符串是一个数学函数而不是恶意代码。
为此,我创建了一个逻辑,将字符串的所有字符与黑名单和白名单进行比较,问题是字符串只能包含特定排列的少数字符,例如 cos
,字符串不能包含 c + o * s
。
whitelist = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '(', ')',
'x', 'y', 'sin', 'cos', 'tg', '+', '-', '*', '/', ' ']
blacklist = ['a', 'b', 'd', 'f', 'h', 'i', 'j', 'k', 'l', 'm', 'p', 'q',
'r', 'u', 'v', 'w', 'z']
def stringTreat(string):
if not any(ch in string for ch in blacklist):
if all(ch in whitelist for ch in string):
print('OK!!')
else:
print('stop at whitelist')
else:
print('stop at blacklist')
string = input('input:')
stringTreat(string)
如果我将 12 + 67 - 82
设置为本示例的输入,则输出为 OK!!
,但如果 cos(x)
code> 是输入,输出更改为 stop at Whitelist
。
如何创建一个逻辑来接受子字符串,例如(sin, cos, tg),字符,例如(0, 1, 2, 3...) 并且不接受其他子字符串和字符,例如(a、f、@、$、ls、mv)?
最佳答案
您尝试构建的内容通常称为解析器,其中有许多您可能会发现有用的既定算法(考虑查看 ply
包)。
通常,这分为两个步骤:分词器和语法。分词器将输入字符串分成几部分,并可能用一些额外信息来标记它们(例如,12 + cos(3)
可能会变成 [NUM(12), OP(+), FUNC(cos)、LPAREN、NUM(3)、RPAREN]
)。请注意,您可以使用如下正则表达式构建一个非常简单的标记生成器:
In [1]: re.split(r'\b', '12 + 16 - cos(2)')
Out[1]: ['', '12', ' + ', '16', ' - ', 'cos', '(', '2', ')']
In [2]: [v.strip() for v in re.split(r'\b', '12 + 16 - cos(2)') if v.strip()]
Out[2]: ['12', '+', '16', '-', 'cos', '(', '2', ')']
语法然后寻找标记的模式,并可以告诉如何处理它们,通常将它们形成某种“语法树”,以后更容易操作。例如,您可能会将整个函数视为单个一元表达式,EXPR(cos, NUM(3))
,然后将加法运算视为另一个二进制表达式,EXPR(add, NUM (12), EXPR(cos, NUM(3)))
。请注意,这棵树现在很简单:当您遇到表达式时,查看第一个位置的运算符(“add”、“cos”等),然后使用它来确定如何处理剩余的操作数。这些可以递归处理,因此内部表达式解析为某个数字,然后外部表达式可以使用该数字解析为最终的单个数字。
你不必这样做,但是拥有这样的背景表明,不要像你尝试的那样一次性完成所有事情,而是先尝试拥有一个标记生成器,然后你就只有一些标记 STR (cos)
或 STR(ls)
,您可以轻松地将前者识别为有效输入,并在遇到另一个(或不在白名单上的任何其他内容)时抛出错误。
顺便说一句,您通常只有白名单或黑名单,而不是两者都有。白名单通常假设其他任何内容都是无效的,而黑名单则假设其他任何内容都是有效的,因此如果某些内容落入两个列表或都不落入两个列表,那么两者都会带来问题。
最后一点,由于您使用的是 Python,如果您小心并且允许使用通用 Python 语法,则可以使用 eval
和 exec
为您进行解析和执行。例如:
In [1]: import math
In [2]: eval('12 + 16 - cos(2)', {'cos': math.cos}, {})
Out[2]: 28.416146836547142
您可以在这些字典中指定您希望用户有权访问哪些功能,并阻止他们与程序状态中的任何其他内容进行交互。我仍然可能不会这样做,除非你至少有一点信任用户,或者他们只能通过搞砸事情来伤害自己。
关于python - Python中黑名单和白名单的字符串处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57699348/