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

Chr*_*rch 161 python string type-conversion

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

if element.isdigit():
  newelement = int(element)
Run Code Online (Sandbox Code Playgroud)

浮点数更难.现在我正在使用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)
Run Code Online (Sandbox Code Playgroud)

这是有效的,但显然if语句有点像熊.我考虑的另一个解决方案是将转换包装在try/catch块中,看看它是否成功,如本问题所述.

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

dbr*_*dbr 260

我会用...

try:
    float(element)
except ValueError:
    print "Not a float"
Run Code Online (Sandbox Code Playgroud)

..它很简单,而且很有效

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

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

  • 除了你忘了给你的函数命名"will_it_float". (76认同)
  • 你的正则表达式不是最优的."^\d + \.\ d + $"将以与上述相同的速度失败,但会更快地成功.另外,更正确的方法是:"^ [+ - ]?\ d(>?\.\ d +)?$"但是,这仍然不匹配数字:+ 1.0e-10 (9认同)
  • 我认为正则表达式不解析负数. (4认同)
  • @ S.Lott:这个应用的大多数字符串都会成为整数或浮点数. (3认同)
  • 第二种选择不会捕获纳米和指数表达式 - 例如2e3. (3认同)

Eri*_*ski 169

用于检查float的Python方法:

def isfloat(value):
  try:
    float(value)
    return True
  except ValueError:
    return False
Run Code Online (Sandbox Code Playgroud)

不要被隐藏在浮船中的地精弄掉!做单位测试!

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

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
Run Code Online (Sandbox Code Playgroud)

  • 很好的答案.只需在float = True中添加2个:`isfloat("1.23")`和`isfloat("\n\t 1.23 \n\t \n")``.在网络请求中很有用; 不需要先修剪空白区域. (6认同)
  • 另一个可能令人惊讶的补充:`isfloat("1_2_3.4")` -> `True` (3认同)
  • 应该是_any_,而不是_Any_。其他看起来很扎实! (3认同)
  • `isfloat(1<<1024)` 引发 OverflowError... (2认同)

小智 18

'1.43'.replace('.','',1).isdigit()
Run Code Online (Sandbox Code Playgroud)

true只有在有'或'的情况下才会返回.在数字串中.

'1.4.3'.replace('.','',1).isdigit()
Run Code Online (Sandbox Code Playgroud)

将返回 false

'1.ww'.replace('.','',1).isdigit()
Run Code Online (Sandbox Code Playgroud)

将返回 false

  • 不是最佳的,但实际上非常聪明。不会处理 +/- 和指数。 (3认同)
  • @MarkMoretto 当你得知负数的存在时,你会感到震惊 (3认同)
  • `am_i_a_number.strip().lstrip('-').replace('.', '', 1).isdigit()` (3认同)

Pet*_*ore 6

只是为了多样性,这里是另一种方法。

>>> 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
Run Code Online (Sandbox Code Playgroud)

编辑:我确定它不会支持所有浮动情况,但尤其是当有指数时。为了解决它,它看起来像这样。这将返回 True 只有 val 是一个浮点数和 False 为 int 但可能不如正则表达式的性能。

>>> 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
Run Code Online (Sandbox Code Playgroud)


sim*_*eco 6

函数 的简化版本 is_digit(str),在大多数情况下就足够了(不考虑指数表示法“NaN”值):

def is_digit(str):
    return str.lstrip('-').replace('.', '').isdigit()
Run Code Online (Sandbox Code Playgroud)

  • 非常好,优雅 (2认同)

Jac*_*son 5

如果你关心性能(我不建议你应该这样做),基于尝试的方法是明显的赢家(与基于分区的方法或正则表达式方法相比),只要你不期望很多无效字符串,在这种情况下它可能更慢(可能是由于异常处理的成本).

同样,我并不是建议你关心性能,只是在你每秒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()
Run Code Online (Sandbox Code Playgroud)


Set*_*ton 5

TL; DR:

  • 如果您的输入主要是可以转换为浮点数的字符串,try: except:方法是最好的本机Python方法.
  • 如果您的输入主要是无法转换为浮点数的字符串,则正则表达式或分区方法会更好.
  • 如果您1)不确定您的输入或需要更高的速度2)不介意并且可以安装第三方C扩展,fastnumbers工作得很好.

还有另一种方法可以通过称为fastnumbers的第三方模块(披露,我是作者); 它提供了一个名为isfloat的函数.我在这个答案中采用了Jacob Gabrielson概述的单元测试示例,但添加了该fastnumbers.isfloat方法.我还应该注意到雅各布的例子并没有公正地使用正则表达式选项,因为该例子中的大多数时间都花在了全局查找上,因为点运算符...我修改了这个函数以给出更公平的比较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()
Run Code Online (Sandbox Code Playgroud)

在我的机器上,输出是:

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
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,正则表达式实际上没有它最初看起来那么糟糕,如果你真的需要速度,那么这种fastnumbers方法非常好.