我正在解析一个xml文件,其中我获得了基本表达式(如id*10+2
)。我想要做的是评估表达式以实际获得值。为此,我使用了eval()
方法,该方法非常有效。
唯一的问题是数字实际上是十六进制数字。如果每个十六进制数字都以'0x'为前缀,eval()
方法可以很好地工作,但我找不到办法,我也不能在这里找到类似的问题。如何以干净的方式完成?
答案 0 :(得分:4)
使用re
模块。
>>> import re
>>> re.sub(r'([\dA-F]+)', r'0x\1', 'id*A+2')
'id*0xA+0x2'
>>> eval(re.sub(r'([\dA-F]+)', r'0x\1', 'CAFE+BABE'))
99772
但请注意,如果eval
输入无效,则无效。还有many risks使用eval
。
如果你的十六进制数字有小写字母,那么你可以使用它:
>>> re.sub(r'(?<!i)([\da-fA-F]+)', r'0x\1', 'id*a+b')
'id*0xa+0xb'
这使用负面的lookbehind断言来确保字母i
不在它试图转换的部分之前(阻止'id'
变成'i0xd'
。替换{{1}如果变量为i
,则I
。
答案 1 :(得分:0)
如果您可以将表达解析为单个数字,那么我建议使用int function:
>>> int("CAFE", 16)
51966
答案 2 :(得分:0)
小心eval
!不要在不受信任的输入中使用它。
如果它只是简单的算术,我会使用自定义解析器(野外有大量的例子)......并且使用解析器生成器(flex / bison,antlr等)是一项有用的技能很容易被遗忘,所以这可能是一个刷新或学习它的好机会。
答案 3 :(得分:0)
一种选择是使用parser
模块:
import parser, token, re
def hexify(ast):
if not isinstance(ast, list):
return ast
if ast[0] in (token.NAME, token.NUMBER) and re.match('[0-9a-fA-F]+$', ast[1]):
return [token.NUMBER, '0x' + ast[1]]
return map(hexify, ast)
def hexified_eval(expr, *args):
ast = parser.sequence2st(hexify(parser.expr(expr).tolist()))
return eval(ast.compile(), *args)
>>> hexified_eval('id*10 + BABE', {'id':0xcafe})
567466
这比正则表达式解决方案更简洁,因为它只会尝试替换已被确定为名称或数字(并且看起来像十六进制数字)的标记。它还可以正确处理更常见的python表达式,例如id*10 + len('BABE')
(它不会将'BABE'
替换为'0xBABE'
)。
OTOH,正则表达式解决方案更简单,可能涵盖您需要处理的所有案例。