检查一个string是否可以转换为在Python中浮动

我有一些Python代码运行通过一个string列表,并将其转换为整数或浮点数,如果可能的话。 这样做整数是很容易的

if element.isdigit(): newelement = int(element) 

浮点数更难。 现在我正在使用partition('.')来分割string,并检查以确保一方或双方都是数字。

 partition = element.partition('.') if (partition[0].isdigit() and partition[1] == '.' and partition[2].isdigit()) or (partition[0] == '' and partition[1] == '.' and partition[2].isdigit()) or (partition[0].isdigit() and partition[1] == '.' and partition[2] == ''): newelement = float(element) 

这是有效的,但显然,如果这种说法是有点熊。 我考虑的另一个解决scheme就是将转换包装在try / catch块中,看看它是否成功,就像这个问题所描述的那样。

任何人有任何其他的想法? 关于分区和try / catch方法相对优点的意见?

我只是使用..

 try: float(element) except ValueError: print "Not a float" 

它很简单,而且工作

另一种select是正则expression式:

 import re if re.match("^\d+?\.\d+?$", element) is None: print "Not float" 

检查float的Python方法:

 def isfloat(value): try: float(value) return True except ValueError: return False 

不要被隐藏在浮船上的地精咬伤! 做单位testing!

什么是,而不是一个浮动可能会让你感到惊讶:

 Command to parse Is it a float? Comment -------------------------------------- --------------- ------------ print(isfloat("")) False print(isfloat("1234567")) True print(isfloat("NaN")) True nan is also float print(isfloat("NaNananana BATMAN")) False print(isfloat("123.456")) True print(isfloat("123.E4")) True print(isfloat(".1")) True print(isfloat("1,234")) False print(isfloat("NULL")) False case insensitive print(isfloat(",1")) False print(isfloat("123.EE4")) False print(isfloat("6.523537535629999e-07")) True print(isfloat("6e777777")) True This is same as Inf print(isfloat("-iNF")) True print(isfloat("1.797693e+308")) True print(isfloat("infinity")) True print(isfloat("infinity and BEYOND")) False print(isfloat("12.34.56")) False Two dots not allowed. print(isfloat("#56")) False print(isfloat("56%")) False print(isfloat("0E0")) True print(isfloat("x86E0")) False print(isfloat("86-5")) False print(isfloat("True")) False Boolean is not a float. print(isfloat(True)) True Boolean is a float print(isfloat("+1e1^5")) False print(isfloat("+1e1")) True print(isfloat("+1e1.3")) False print(isfloat("+1.3P1")) False print(isfloat("-+1")) False print(isfloat("(1)")) False brackets not interpreted 

如果你关心性能(而且我不build议你应该这样做),那么基于尝试的方法是明显的赢家(与基于分区的方法或正则expression式方法相比),只要你不期望有很多无效的string,在这种情况下,它可能会更慢(大概是由于exception处理的成本)。

再说一次,我并不是build议你关心性能,只要给你提供数据,以防万一你每秒做100亿次这样的事情。 此外,基于分区的代码不处理至less一个有效的string。

 $ ./floatstr.py
 F..
分区悲伤:3.1102449894
分区开心:2.09208488464
 ..
重新伤心:7.76906108856
重新开心:7.09421992302
 ..
尝试伤心:12.1525540352
试试开心:1.44165301323
 。
 ================================================== ====================
 FAIL:test_partition(__main __。ConvertTests)
 -------------------------------------------------- --------------------
回溯(最近一次通话最后):
  在test_partition文件“./floatstr.py”,第48行
     self.failUnless(is_float_partition( “20E2”))
 Asse田

 -------------------------------------------------- --------------------
在33.670s跑8次testing

失败(失败= 1)

这里是代码(Python 2.6,正则expression式取自John Gietzen的答案 ):

 def is_float_try(str): try: float(str) return True except ValueError: return False import re _float_regexp = re.compile(r"^[-+]?(?:\b[0-9]+(?:\.[0-9]*)?|\.[0-9]+\b)(?:[eE][-+]?[0-9]+\b)?$") def is_float_re(str): return re.match(_float_regexp, str) def is_float_partition(element): partition=element.partition('.') if (partition[0].isdigit() and partition[1]=='.' and partition[2].isdigit()) or (partition[0]=='' and partition[1]=='.' and pa\ rtition[2].isdigit()) or (partition[0].isdigit() and partition[1]=='.' and partition[2]==''): return True if __name__ == '__main__': import unittest import timeit class ConvertTests(unittest.TestCase): def test_re(self): self.failUnless(is_float_re("20e2")) def test_try(self): self.failUnless(is_float_try("20e2")) def test_re_perf(self): print print 're sad:', timeit.Timer('floatstr.is_float_re("12.2x")', "import floatstr").timeit() print 're happy:', timeit.Timer('floatstr.is_float_re("12.2")', "import floatstr").timeit() def test_try_perf(self): print print 'try sad:', timeit.Timer('floatstr.is_float_try("12.2x")', "import floatstr").timeit() print 'try happy:', timeit.Timer('floatstr.is_float_try("12.2")', "import floatstr").timeit() def test_partition_perf(self): print print 'partition sad:', timeit.Timer('floatstr.is_float_partition("12.2x")', "import floatstr").timeit() print 'partition happy:', timeit.Timer('floatstr.is_float_partition("12.2")', "import floatstr").timeit() def test_partition(self): self.failUnless(is_float_partition("20e2")) def test_partition2(self): self.failUnless(is_float_partition(".2")) def test_partition3(self): self.failIf(is_float_partition("1234x.2")) unittest.main() 

TL; DR

  • 如果你的input大部分是可以转换为浮点数的string, try: except:方法是最好的本地Python方法。
  • 如果你的input大多是不能转换为浮点数的string, 那么正则expression式或分区方法会更好。
  • 如果你是1)不确定你的input或需要更多的速度和2)不介意,并可以安装第三方C扩展, 快速数字工作得很好。

还有另一种方法可以通过第三方模块fastnumbers (披露,我是作者); 它提供了一个叫做isfloat的函数。 我在这个答案中采用了Jacob Gabrielson提出的unit testing例子,但是添加了fastnumbers.isfloat方法。 我还应该注意到,雅各布的例子并没有公正的正则expression式的选项,因为在这个例子中的大部分时间都花在全局查找,因为点运算符…我已经修改了这个函数给一个更公平的比较try: except:


 def is_float_try(str): try: float(str) return True except ValueError: return False import re _float_regexp = re.compile(r"^[-+]?(?:\b[0-9]+(?:\.[0-9]*)?|\.[0-9]+\b)(?:[eE][-+]?[0-9]+\b)?$").match def is_float_re(str): return True if _float_regexp(str) else False def is_float_partition(element): partition=element.partition('.') if (partition[0].isdigit() and partition[1]=='.' and partition[2].isdigit()) or (partition[0]=='' and partition[1]=='.' and partition[2].isdigit()) or (partition[0].isdigit() and partition[1]=='.' and partition[2]==''): return True else: return False from fastnumbers import isfloat if __name__ == '__main__': import unittest import timeit class ConvertTests(unittest.TestCase): def test_re_perf(self): print print 're sad:', timeit.Timer('ttest.is_float_re("12.2x")', "import ttest").timeit() print 're happy:', timeit.Timer('ttest.is_float_re("12.2")', "import ttest").timeit() def test_try_perf(self): print print 'try sad:', timeit.Timer('ttest.is_float_try("12.2x")', "import ttest").timeit() print 'try happy:', timeit.Timer('ttest.is_float_try("12.2")', "import ttest").timeit() def test_fn_perf(self): print print 'fn sad:', timeit.Timer('ttest.isfloat("12.2x")', "import ttest").timeit() print 'fn happy:', timeit.Timer('ttest.isfloat("12.2")', "import ttest").timeit() def test_part_perf(self): print print 'part sad:', timeit.Timer('ttest.is_float_partition("12.2x")', "import ttest").timeit() print 'part happy:', timeit.Timer('ttest.is_float_partition("12.2")', "import ttest").timeit() unittest.main() 

在我的机器上,输出是:

 fn sad: 0.220988988876 fn happy: 0.212214946747 . part sad: 1.2219619751 part happy: 0.754667043686 . re sad: 1.50515985489 re happy: 1.01107215881 . try sad: 2.40243887901 try happy: 0.425730228424 . ---------------------------------------------------------------------- Ran 4 tests in 7.761s OK 

正如你所看到的,正则expression式实际上并不像它最初看起来那么糟糕,如果你真的需要速度, fastnumbers方法是相当不错的。

这个正则expression式将检查科学浮点数:

 ^[-+]?(?:\b[0-9]+(?:\.[0-9]*)?|\.[0-9]+\b)(?:[eE][-+]?[0-9]+\b)?$ 

不过,我相信你最好的select是尝试使用parsing器。

 '1.43'.replace('.','',1).isdigit() 

只有当有一个或者没有'。'时才会返回true 。 在数字串中。

 '1.4.3'.replace('.','',1).isdigit() 

将返回false

 '1.ww'.replace('.','',1).isdigit() 

将返回false

如果您不需要担心科学或其他数字expression方式,只能使用可能有数字或无数字的string:

function

 def is_float(s): result = False if s.count(".") == 1: if s.replace(".", "").isdigit(): result = True return result 

Lambda版本

 is_float = lambda x: x.replace('.','',1).isdigit() and "." in x 

 if is_float(some_string): some_string = float(some_string) elif some_string.isdigit(): some_string = int(some_string) else: print "Does not convert to int or float." 

这样你就不会不小心把应该是int的东西转换成float。

我使用了已经提到的function,但很快我注意到string为“南”,“Inf”,它的变化被认为是数字。 所以我build议你改进function的版本,这将在这些types的input上返回false,并且不会失败“1e3”变体:

 def is_float(text): try: float(text) # check for nan/infinity etc. if text.isalpha(): return False return True except ValueError: return False 

str(strval).isdigit()似乎很简单。 处理以string或int或floatforms存储的值