【问题标题】: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():来表示正整数?

标签: python string type-conversion


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

                        【讨论】:

                          猜你喜欢
                          • 2010-12-28
                          • 2021-01-28
                          • 2022-10-15
                          • 1970-01-01
                          • 2016-10-07
                          • 1970-01-01
                          • 2011-07-26
                          • 2012-09-10
                          • 2018-07-08
                          相关资源
                          最近更新 更多