在尝试完成Codesignal上的“可逆括号”挑战约2天,并提出了150多个行无效的代码后,我偶然发现了以下使用eval()的代码。
现在,我知道eval()接受一个字符串并将其解释为好像已将其输入到控制台中。但是我真的不明白它是如何实现其目标的。有人可以一点一点地解释一下发生了什么吗?
谢谢
我尝试使用谷歌搜索,阅读文档并搜索youtube以获得更好的理解。但无济于事。
def reverseInParentheses(s):
return eval('"' + s.replace('(', '"+("').replace(')', '")[::-1]+"') + '"')
inputString = "(bar)"
reverseInParentheses(inputString) # output: "rab"
inputString = "foo(bar)baz"
reverseInParentheses(inputString) # output: "foorabbaz"
inputString = "foo(bar)baz(blim)"
reverseInParentheses(inputString) # output: "foorabbazmilb"
inputString = "foo(bar(baz))blim"
reverseInParentheses(inputString) # output: "foobazrabblim"
让我们一一剖析:
eval('"' + s.replace('(', '"+("').replace(')', '")[::-1]+"') + '"')
这实际上与以下内容相同(这可能使它更容易理解):
code = '"' + s.replace('(', '"+("').replace(')', '")[::-1]+"') + '"'
eval(code)
与以下内容相同:
innerCode = s.replace('(', '"+("').replace(')', '")[::-1]+"')
code = '"' + innerCode + '"'
eval(code)
innerCode
在那里进行简单的字符串操作:
(
为"+("
)
为")[::-1]+"
因此,以您的示例(bar)
为例,结果如下:"+("bar")[::-1]+"
如果再次添加引号,则会得到以下字符串:
""+("bar")[::-1]+""
= ("bar")[::-1]
= "bar"[::-1]
什么[::-1]
做一个字符串为扭转这种局面,基本上是由从后面迭代它(这是什么-1
呢):
>>> 'foo'[::-1]
'oof'
>>> 'bar'[::-1]
'rab'
然后使用来执行生成的代码时eval
,您将得到结果。
让我们来看另一个示例:foo(bar)baz(blim)
。替换括号后,您将得到:
foo"+("bar")[::-1]+"baz"+("blim")[::-1]+"
添加引号并将其简化,您将获得以下信息:
"foo"+("bar")[::-1]+"baz"+("blim")[::-1]+""
= "foo" + ("bar")[::-1] + "baz" + ("blim")[::-1]
= "foo" + "bar"[::-1] + "baz" + "blim"[::-1]
执行该操作时,您会得到"foo" + "rab" + "baz" + "milb"
。
请注意,尽管这样做可以解决工作,但是使用eval
实际上是一个非常糟糕的主意。eval
执行任何代码,而不仅仅是字符串连接和字符串反转。因此,如果您从盲目信任的来源获取输入,则攻击者可能会以此来执行错误的代码。
完全不执行此行为是一个更好的主意eval
,这并不是那么困难,因为您毕竟只是在操纵一个字符串。
例如,使用正则表达式快速查找括号:
import re
def reverseInParentheses(s):
for m in re.findall('\((.*?)\)', s):
s = s.replace('(' + m + ')', m[::-1])
return s
>>> reverseInParentheses("(bar)")
'rab'
>>> reverseInParentheses("foo(bar)baz")
'foorabbaz'
>>> reverseInParentheses("foo(bar)baz(blim)")
'foorabbazmilb'
>>> reverseInParentheses("foo(bar(baz))blim")
'foozab(rab)blim'
请注意,这对于带有嵌套括号的最后一个示例不正确。对于这种情况,最好使用适当的解析器,例如pyparsing
。这在另一个问题的答案中有更详细的描述。
我强烈建议您不要在eval
这里使用,即使它确实适合您的情况。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句