检查字符串是不是可以在 Python 中转换为浮点数

Posted

技术标签:

【中文标题】检查字符串是不是可以在 Python 中转换为浮点数【英文标题】:Checking if a string can be converted to float in Python检查字符串是否可以在 Python 中转换为浮点数 【发布时间】:2010-10-18 16:10:27 【问题描述】:

我有一些 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 块中并查看它是否成功,如this question 中所述。

有人有其他想法吗?对分区和 try/catch 方法的优缺点有何看法?

【问题讨论】:

准确地说,Python 中没有类型转换之类的东西。所以标签type-conversion 具有误导性,在某些语言中这是一个定义明确的术语。 @bombs 没有类型转换?那你怎么称呼它:print(type("1"));print(type(int("1"))),输出:<class 'str'><class 'int'>?这不是从strint 的类型转换吗? @ggorlen 一点也不。您只是从其他对象创建新对象。在此过程中,您会在堆中分配新的内存空间。没有任何东西被转换。 我明白你的意思,但这对我来说似乎很迂腐。如果有人说“将字符串转换为浮动”,其意图似乎非常明确。 你为什么用.isdigit()而不是.isnumeric():来表示正整数? 【参考方案1】:

我会用..

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

..它很简单,而且很有效。请注意,如果元素是例如它仍然会抛出溢出错误。 1

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

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

【讨论】:

@S.Lott:应用到的大多数字符串都是整数或浮点数。 您的正则表达式不是最佳的。 "^\d+\.\d+$" 将以与上述相同的速度使匹配失败,但会更快地成功。此外,更正确的方法是: "^[+-]?\d(>?\.\d+)?$" 但是,这仍然与以下数字不匹配:+1.0e-10 除了您忘记将函数命名为“will_it_float”。 第二个选项不会捕获 nan 和指数表达式 - 例如 2e3。 我认为正则表达式没有解析负数。【参考方案2】:

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

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

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

【讨论】:

【参考方案3】:

如果您关心性能(我不建议您这样做),那么基于 try 的方法显然是赢家(与您的基于分区的方法或正则表达式方法相比),只要您不期望大量无效字符串,在这种情况下它可能会变慢(可能是由于异常处理的成本)。

再说一次,我并不是建议您关心性能,只是为您提供数据,以防您每秒执行 100 亿次或其他操作。此外,基于分区的代码不能处理至少一个有效字符串。

$ ./floatstr.py F.. 分区伤心:3.1102449894 分区快乐:2.09208488464 .. 再伤心:7.76906108856 重新开心:7.09421992302 .. 尝试悲伤:12.1525540352 尝试快乐:1.44165301323 . ==================================================== ===================== 失败:test_partition (__main__.ConvertTests) -------------------------------------------------- -------------------- 回溯(最近一次通话最后): 文件“./floatstr.py”,第 48 行,在 test_partition self.failUnless(is_float_partition("20e2")) 断言错误 -------------------------------------------------- -------------------- 在 33.670 秒内运行 8 次测试 失败(失败=1)

这是代码(Python 2.6,正则表达式取自 John Gietzen 的 answer):

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()

【讨论】:

【参考方案4】:

检查浮点数的 Python 方法:

def is_float(element: Any) -> bool:
    try:
        float(element)
        return True
    except ValueError:
        return False

始终进行单元测试。什么是浮动,什么不是浮动可能会让您感到惊讶:

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

【讨论】:

很好的答案。只需在 float=True 的情况下再添加 2 个:isfloat(" 1.23 ")isfloat(" \n \t 1.23 \n\t\n")。在网络请求中很有用;无需先修剪空白。 另一个可能令人惊讶的补充:isfloat("1_2_3.4") -> True 您可能还想排除 isfloat(Noneisfloat(False) 的类型错误编辑:删除了我的代码示例,因为多行格式非常混乱。 @dariober 为什么?【参考方案5】:

TL;DR

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

还有另一种方法可以通过名为fastnumbers 的第三方模块获得(披露,我是作者);它提供了一个名为isfloat 的函数。我采用了 Jacob Gabrielson 在this answer 中概述的单元测试示例,但添加了fastnumbers.isfloat 方法。我还应该注意到,Jacob 的示例对正则表达式选项不公平,因为该示例中的大部分时间都用于全局查找,因为点运算符...我修改了该函数以提供与 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

如您所见,正则表达式实际上并不像最初看起来那么糟糕,如果您真的需要速度,fastnumbers 方法相当不错。

【讨论】:

如果您有大部分无法转换为浮点数的字符串,快速数字检查效果很好,真的可以加快速度,谢谢 命名变量str会覆盖内置函数。【参考方案6】:

如果您不需要担心数字的科学或其他表达式,并且只使用可以是带句点或不带句点的数字的字符串:

功能

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。

【讨论】:

你也可以这样放置和操作。 def is_float(s): result = False if s.count(".") == 1 and s.replace(".", "").isdigit(): result = True 返回结果【参考方案7】:
'1.43'.replace('.','',1).isdigit()

只有在有或没有'.'时才会返回true在数字串中。

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

将返回false

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

将返回false

【讨论】:

不是最佳但实际上非常聪明。不会处理 +/- 和指数。 晚了几年,但这是一个不错的方法。在熊猫数据框中使用以下内容为我工作:[i for i in df[i].apply(lambda x: str(x).replace('.','').isdigit()).any()] @MarkMoretto 当你知道负数的存在时你会感到震惊 最适合我的场景的单线,我只需要检查正浮点数或数字。我喜欢。【参考方案8】:
str(strval).isdigit()

似乎很简单。

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

【讨论】:

输入 [2]: '123,123'.isdigit() 输出[2]: False 它不适用于负数文字,请修正您的答案 '39.1'.isdigit() all([x.isdigit() for x in str(VAR).strip('-').replace(',','.').split('.')])如果您正在寻找更完整的实现。【参考方案9】:

我使用了已经提到的函数,但很快我注意到字符串为“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

【讨论】:

我们不能立即从if text.isalpha(): 检查开始吗? 顺便说一句,我也需要同样的东西:我不想接受 NaN、Inf 之类的东西【参考方案10】:

我一直在寻找一些类似的代码,但看起来使用 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: ")

【讨论】:

【参考方案11】:

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

>>> 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

编辑:我确信它不会支持所有的浮动情况,尤其是当有指数时。为了解决这个问题,它看起来像这样。这将返回 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

【讨论】:

isnumeric 函数看起来是个糟糕的选择,因为它在各种 Unicode 字符(如分数)上返回 true。文档说:“数字字符包括数字字符,以及所有具有 Unicode 数值属性的字符,例如 U+2155, VULGAR FRACTION ONE FIFTH”【参考方案12】:

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

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

【讨论】:

非常漂亮,优雅【参考方案13】:

尝试转换为浮点数。如果有错误,打印 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'

【讨论】:

【参考方案14】:

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

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

【讨论】:

【参考方案15】:

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


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

【讨论】:

虽然此代码可以解决问题,including an explanation 说明如何以及为什么解决问题将真正有助于提高您的帖子质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提问的人。请edit您的答案添加解释并说明适用的限制和假设。【参考方案16】:

我尝试了上面一些简单的选项,围绕转换为浮点数使用了try测试,发现大部分回复都有问题。

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

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

【讨论】:

【参考方案17】:

我们可以使用正则表达式: import re if re.match('[0-9]*.?[0-9]+', <your_string>): print("Its a float/int") else: print("Its something alien") 让我用英语解释一下正则表达式,

* -> 0 次或多次出现 + -> 1 次或多次出现 ? -> 0/1 出现

现在,让我们转换

'[0-9]* -> 让 0-9 之间出现 0 个或多个数字 \.? -> 后跟一个 0 或一个 '.'(如果您需要检查它是否可以是 int/float 或者我们也可以使用代替 ?,请使用 1) [0-9]+ -> 后跟 0-9 之间出现 0 个或多个数字

【讨论】:

【参考方案18】:

似乎很多正则表达式都错过了一件事或另一件事。到目前为止,这一直对我有用:

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

它允许无穷大(或 inf),符号、nan、前面没有数字 小数和前导/尾随空格(如果需要)。 ^$ 是 需要避免将1.2f-2 之类的内容部分匹配为1.2

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

【讨论】:

【参考方案19】:

我找到了一种可行的方法。需要验证这一点。第一次在这里放东西。

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

【讨论】:

【参考方案20】:

这就像一个魅力:

[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]

【讨论】:

【参考方案21】:

我已经编写了自己的函数。我使用 floatN() 或 floatZ() 而不是 float(value)。如果不能将值转换为浮点数,则返回 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()。显然,您可以将此技术用于您需要的任何强制转换函数。

【讨论】:

【参考方案22】:

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

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 中的最后一个值包含小数位的假设。

【讨论】:

以上是关于检查字符串是不是可以在 Python 中转换为浮点数的主要内容,如果未能解决你的问题,请参考以下文章

在 Python 2.x 中,是不是有办法检查字符串是不是可以转换为整数? [复制]

python pandas中如何将dataframe中的一列字符串类型转换为浮点类型?

猫鼬和浮点值

从浮点字符串到 Int 的 Python 类型转换在创建列表时无法在 for 循环中工作

将浮点 numpy 数组转换为字符串数组 Python

python类型检查和类型转换