我正在创建一个程序,并且需要创建一个逻辑来处理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)
输入为,则输出更改为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,因此请谨慎使用,eval
并且可以使用一般的Python语法,然后可以使用和exec
为您执行解析和执行。例如:
In [1]: import math
In [2]: eval('12 + 16 - cos(2)', {'cos': math.cos}, {})
Out[2]: 28.416146836547142
您可以在这些词典中指定希望用户访问哪些功能,并阻止它们与程序状态下的任何其他事物进行交互。除非您对用户至少有一点信任,或者他们只能通过搞砸自己而伤害自己,否则我可能还是不会这样做。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句