检查一个字符串是否可以在Python中转换为float

我有一些Python代码,它运行一个字符串列表,并将它们转换为整数或浮点数(如果可能的话)。对整数执行此操作非常简单

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

浮点数比较难。现在我正在使用partition('.')来分割字符串,并检查以确保一侧或两侧都是数字。

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)

这是可行的,但显然if语句有点麻烦。我考虑的另一个解决方案是将转换包装在try/catch块中,并查看它是否成功,如这个问题所述。

有人有其他想法吗?对分区和尝试/捕获方法的相对优点有什么看法?

481374 次浏览

我会用。

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

..这很简单,也很有效。注意,如果element是例如1<<1024,它仍然会抛出OverflowError。

另一种选择是正则表达式:

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

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

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

但是,我认为最好的办法是尝试使用解析器。

如果您关心性能(我并不建议您应该这样做),基于try的方法显然是赢家(与基于分区的方法或regexp方法相比),只要您不期望出现大量无效字符串,在这种情况下,它可能会更慢(大概是由于异常处理的成本)。

再说一次,我不是建议你关心性能,只是给你数据以防你每秒做100亿次。而且,基于分区的代码不处理至少一个有效字符串。

$ ./floatstr.py
F..
partition sad: 3.1102449894
partition happy: 2.09208488464
..
re sad: 7.76906108856
re happy: 7.09421992302
..
try sad: 12.1525540352
try happy: 1.44165301323
.
======================================================================
FAIL: test_partition (__main__.ConvertTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "./floatstr.py", line 48, in test_partition
self.failUnless(is_float_partition("20e2"))
AssertionError


----------------------------------------------------------------------
Ran 8 tests in 33.670s


FAILED (failures=1)

下面是代码(Python 2.6, regexp来自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()

Python3方法检查float:

def is_float(element: any) -> bool:
#If you expect None to be passed:
if element is None:
return False
try:
float(element)
return True
except ValueError:
return False

上面的Python2版本:如何将字符串解析为浮点数或int数?

总是做单元测试。什么是浮点数,什么不是浮点数,你可能会感到惊讶:

Command to parse                        Is it a float?  Comment
--------------------------------------  --------------- ------------
print(isfloat(""))                      False
print(isfloat("1234567"))               True
print(isfloat("1_2_3.4"))               True        123.4, underscores ignored
print(isfloat("NaN"))                   True        nan is also float
print(isfloat("123.456"))               True
print(isfloat("123.E4"))                True
print(isfloat(".1"))                    True
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("1,234"))                 False
print(isfloat("NULL"))                  False       case insensitive
print(isfloat("NaNananana BATMAN"))     False
print(isfloat(",1"))                    False
print(isfloat("123.EE4"))               False
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

像这样的下沉异常是不好的,因为杀死金丝雀是不好的,因为float方法可能会因为用户输入以外的原因而失败。不要在生命关键软件上使用这样的代码。此外,python已经改变了它的合同,什么unicode字符串可以提升为浮动,所以预计这段代码的行为将在主要版本更新中发生变化。

博士TL;:

  • 如果你的输入大部分是可以被转换为浮点数的字符串,try: except:方法是最好的Python本机方法。
  • 如果你的输入主要是不能被转换为浮点数的字符串,正则表达式或分区方法将更好。
  • 如果你1)不确定你的输入或需要更快的速度,2)不介意,可以安装第三方c扩展,fastnumbers工作得很好。

还有另一种方法可以通过第三方模块fastnumbers(公开,我是作者);它提供了一个名为isfloat的函数。我已经采用了Jacob Gabrielson在这个答案中概述的unittest示例,但添加了fastnumbers.isfloat方法。我还应该指出,Jacob的例子并没有公正地使用regex选项,因为该例子中的大部分时间都花在了全局查找上,因为点运算符……我修改了该函数,以便与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

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

如果你不需要担心科学或其他数字的表达式,并且只处理可以是带句号或不带句号的数字的字符串:

函数

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型转换为浮点型。

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

,只有当有或没有`时才返回true。'在数字字符串中。
< br >

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

将返回false
< br >

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

将返回false

str(strval).isdigit()

似乎很简单。

处理存储为字符串或整型或浮点数的值

我使用了前面提到的函数,但很快我注意到字符串“Nan”,“Inf”和它的变化被认为是数字。所以我建议你改进版本的函数,它将在这些类型的输入上返回false,并且不会失败的“1e3”变体:

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

我正在寻找一些类似的代码,但看起来使用try/excepts是最好的方法。 这是我正在使用的代码。它包括一个在输入无效时的重试函数。我需要检查输入是否大于0,如果是,则将其转换为浮点数

def cleanInput(question,retry=False):
inputValue = input("\n\nOnly positive numbers can be entered, please re-enter the value.\n\n{}".format(question)) if retry else input(question)
try:
if float(inputValue) <= 0 : raise ValueError()
else : return(float(inputValue))
except ValueError : return(cleanInput(question,retry=True))




willbefloat = cleanInput("Give me the number: ")

为了多样化,这里有另一种方法。

>>> all([i.isnumeric() for i in '1.2'.split('.',1)])
True
>>> all([i.isnumeric() for i in '2'.split('.',1)])
True
>>> all([i.isnumeric() for i in '2.f'.split('.',1)])
False

编辑:我相信它不会支持所有情况下的浮动,虽然特别是当有一个指数。解出来是这样的。只有val是浮点类型时返回True, int类型返回False,但性能可能不如regex。

>>> def isfloat(val):
...     return all([ [any([i.isnumeric(), i in ['.','e']]) for i in val],  len(val.split('.')) == 2] )
...
>>> isfloat('1')
False
>>> isfloat('1.2')
True
>>> isfloat('1.2e3')
True
>>> isfloat('12e3')
False

简化版的函数 is_digit(str),它在大多数情况下都足够(不考虑指数的符号“南”值):

def is_digit(str):
return str.lstrip('-').replace('.', '').isdigit()

尝试转换为float。如果有错误,打印ValueError异常。

try:
x = float('1.23')
print('val=',x)
y = float('abc')
print('val=',y)
except ValueError as err:
print('floatErr;',err)

输出:

val= 1.23
floatErr: could not convert string to float: 'abc'

传递dictionary作为参数,它将转换可以转换为float的字符串,并保留其他字符串

def covertDict_float(data):
for i in data:
if data[i].split(".")[0].isdigit():
try:
data[i] = float(data[i])
except:
continue
return data

你可以使用try-except-else子句,这将捕获当传递的值不能转换为浮点数时引发的任何转换/值错误


  def try_parse_float(item):
result = None
try:
float(item)
except:
pass
else:
result = float(item)
return result

我尝试了上面的一些简单的选项,使用了一个尝试测试转换为浮点数,并发现在大多数回复中有一个问题。

简单测试(按照上面的答案):

entry = ttk.Entry(self, validate='key')
entry['validatecommand'] = (entry.register(_test_num), '%P')


def _test_num(P):
try:
float(P)
return True
except ValueError:
return False

问题出现在:

  • 输入“-”来开始一个负数:

然后你尝试float('-')失败

  • 你输入一个数字,然后尝试删除所有的数字

然后尝试float(''),同样也失败了

我的快速解决方案是:

def _test_num(P):
if P == '' or P == '-': return True
try:
float(P)
return True
except ValueError:
return False
我们可以使用regex作为: 进口再保险 如果re.match([0 - 9] *。?[0 - 9] + ' & lt; your_string>): 打印("Its a float/int") 其他: 打印(“it something alien”;) 让我用英文解释一下正则表达式,

  • *→0或更多的发生
  • +→1次或1次以上
  • ? →0/1发生

现在,让我们进行转换

  • “[0 - 9]*→假设0-9之间有0个或更多的数字出现
  • \。→后面跟着一个0或1 '。'(如果你需要检查它是否可以是int/float,否则我们也可以使用?,使用{1})
  • [0 - 9] +→后面跟着0个或多个0-9之间的数字

似乎很多正则表达式都错过了这样或那样的事情。到目前为止,这对我来说是有效的:

(?i)^\s*[+-]?(?:inf(inity)?|nan|(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?)\s*$

它允许无穷大(或无穷大)与符号,nan,前没有数字 十进制,以及前导/尾随空格(如果需要)。^$是 需要避免将1.2f-2部分匹配为1.2.

如果你需要解析一些文件,你可以使用[ed]而不是e 其中D用于双精度科学计数法。你会 想要更换它之后或只是更换他们之前检查,因为 float()函数不允许

我找到了一个同样有效的方法。需要核实这一点。第一次在这里放东西。

def isfloat(a_str):
try:
x=float(a_str)
if x%1 == 0:
return False
elif x%1 != 0: #an else also do
return True
except Exception as error:
return False

这就像一个魅力:

[dict([a,int(x) if isinstance(x, str)
and x.isnumeric() else float(x) if isinstance(x, str)
and x.replace('.', '', 1).isdigit() else x] for a, x in json_data.items())][0]

我写了自己的函数。而不是float(value),我使用floatN()或floatZ()。如果该值不能被转换为浮点类型,则返回None或0.0。我将它们保存在一个称为safeCasts的模块中。

def floatN(value):
try:
if value is not None:
fvalue = float(value)
else:
fvalue = None
except ValueError:
fvalue = None


return fvalue




def floatZ(value):
try:
if value is not None:
fvalue = float(value)
else:
fvalue = 0.0
except ValueError:
fvalue = 0.0


return fvalue

在其他模块中,我导入它们

from safeCasts import floatN, floatZ

然后使用floatN(value)或floatZ(value)来代替float()。显然,您可以将此技术用于所需的任何强制转换函数。

这是一个简单而有趣的问题。下面给出的解决方案对我来说很好:

import re


val = "25,000.93$"


regex = r"\D"


splitted = re.split(regex, val)
splitted = list(filter(str.isdecimal, splitted))


if splitted:
if len(splitted) > 1:
splitted.insert(-1, ".")


try:
f = float("".join(splitted))
print(f, "is float.")
        

except ValueError:
print("Not a float.")
        

else:
print("Not a float.")

重要提示:此解决方案基于splitted的最后一个值包含小数的假设。

一个简单的函数,不需要try和except操作就可以得到数字的类型

def number_type(number):
if number.isdigit():
return int(number)
elif number.replace(".","").isdigit():
return float(number)
else:
return(type(number))

您可以创建一个函数isfloat(),并在整数和浮点数中使用isdigit(),但不能使用您期望的字符串。

a = raw_input('How much is 1 share in that company? \n')


def isfloat(num):
try:
float(num)
return True
except:
return False
       

while not isfloat(a):
print("You need to write a number!\n")
a = raw_input('How much is 1 share in that company? \n')