Python中atoi / atof的等价方法
Python在处理错误时非常喜欢抛出异常,这通常是件好事。不过,我现在遇到了一些字符串,我非常想把它们转换成整数,就像C语言里的atoi和atof那样。例如,"3 of 12"、"3/12"、"3 / 12"这些字符串都应该变成3;而atof("3.14 seconds")应该变成3.14;atoi(" -99 score")应该变成-99。Python当然有自己的atoi和atof函数,但它们的行为和C语言的完全不同,更像是Python自己的int和float构造函数。
到目前为止,我找到的解决方案真的很丑,而且很难扩展到各种浮点数格式:
value = 1
s = str(s).strip()
if s.startswith("-"):
value = -1
s = s[1:]
elif s.startswith("+"):
s = s[1:]
try:
mul = int("".join(itertools.takewhile(str.isdigit, s)))
except (TypeError, ValueError, AttributeError):
mul = 0
return mul * value
7 个回答
8
我觉得循环的写法比递归的写法要好。
# Iterative
def atof(s):
s,_,_=s.partition(' ') # eg. this helps by trimming off at the first space
while s:
try:
return float(s)
except:
s=s[:-1]
return 0.0
# Recursive
def atof(s):
try:
return float(s)
except:
if not s:
return 0.0
return atof(s[:-1])
print atof("3 of 12")
print atof("3/12")
print atof("3 / 12")
print atof("3.14 seconds")
print atof("314e-2 seconds")
print atof("-99 score")
print atof("hello world")
40
如果你特别想要实现和C语言中的atoi
一样的功能,为什么不直接使用它呢?比如,在我的Mac上,
>>> import ctypes, ctypes.util
>>> whereislib = ctypes.util.find_library('c')
>>> whereislib
'/usr/lib/libc.dylib'
>>> clib = ctypes.cdll.LoadLibrary(whereislib)
>>> clib.atoi('-99foobar')
-99
在Linux、Windows等系统上,类似的代码也应该能正常工作,只是如果你查看whereislib
,你会看到不同的路径(只有在非常特殊的安装情况下,这段代码才可能找不到C运行时库)。
如果你想避免直接使用C库,我想你可以用正则表达式(RE)抓取相关的前缀,比如用r'\s*([+-]?\d+)'
,然后尝试用int
来处理它。
4
用正则表达式来做这个事情其实很简单:
>>> import re
>>> p = re.compile(r'[^\d-]*(-?[\d]+(\.[\d]*)?([eE][+-]?[\d]+)?)')
>>> def test(seq):
for s in seq:
m = p.match(s)
if m:
result = m.groups()[0]
if "." in result or "e" in result or "E" in result:
print "{0} -> {1}".format(s, float(result))
else:
print '"{0}" -> {1}'.format(s, int(result))
else:
print s, "no match"
>>> test(s)
"1 0" -> 1
"3 of 12" -> 3
"3 1/2" -> 3
"3/12" -> 3
3.15 seconds -> 3.15
3.0E+102 -> 3e+102
"what about 2?" -> 2
"what about -2?" -> -2
2.10a -> 2.1