如何将字符串解析为浮点数或整数?

2719

19
通常情况下,如果你在Python中有一个对象,并且想将其转换为该类型的对象,请对其调用 type(my_object)。结果通常可以作为函数调用来执行转换。例如,type(100) 的结果是 int,因此你可以调用 int(my_object) 来尝试将 my_object 转换为整数。这种方法并不总是可行的,但在编码时是一个好的“第一推荐”。 - robertlayton
还要确保该字符串实际上可以转换为浮点数。做到这一点的一种方法是编写一个带有try/except块的自定义函数,检查try范围内是否包含return float(str_value) - InfiniteStack
33个回答

3059
>>> a = "545.2222"
>>> float(a)
545.22220000000004
>>> int(float(a))
545

12
为什么结尾有“04”呢?为什么不直接用“00”呢?另外,我的当前版本的Python没有“04”。 - Mangat Rai Modi
76
浮点数在表示小数时本质上是不完美的。有关更多信息,请参见https://dev59.com/MWEh5IYBdhLWcg3w5283 - dokkaebi
27
为什么不直接使用int(a)而是要使用int(float(a)) - 463035818_is_not_a_number
42
使用int(a)将会出现错误,提示该字符串不是一个有效的整数:ValueError: invalid literal for int() with base 10: '545.222',但是从浮点数转换成整数是被支持的。 - David Parks
5
如果您想确保安全,应该处理ValueError - Joe Bobson
显示剩余2条评论

596
Python2检查字符串是否为浮点数的方法:
def is_float(value):
  if value is None:
      return False
  try:
      float(value)
      return True
  except:
      return False

针对is_float的Python3版本,请参见:在Python中检查字符串是否可转换为浮点数

这个函数的更长、更准确的名称可以是:is_convertible_to_float(value)

Python中什么是浮点数,什么不是浮点数可能会让你惊讶:

下面的单元测试是使用python2完成的。请检查Python3对哪些字符串可以转换为浮点数有不同的行为。一个混淆的差异是现在允许任意数量的内部下划线:(float("1_3.4") == float(13.4))是True。

val                   is_float(val) Note
--------------------  ----------   --------------------------------
""                    False        Blank string
"127"                 True         Passed string
True                  True         Pure sweet Truth
"True"                False        Vile contemptible lie
False                 True         So false it becomes true
"123.456"             True         Decimal
"      -127    "      True         Spaces trimmed
"\t\n12\r\n"          True         whitespace ignored
"NaN"                 True         Not a number
"NaNanananaBATMAN"    False        I am Batman
"-iNF"                True         Negative infinity
"123.E4"              True         Exponential notation
".1"                  True         mantissa only
"1_2_3.4"             False        Underscores not allowed
"12 34"               False        Spaces not allowed on interior
"1,234"               False        Commas gtfo
u'\x30'               True         Unicode is fine.
"NULL"                False        Null is not special
0x3fade               True         Hexadecimal
"6e7777777777777"     True         Shrunk to infinity
"1.797693e+308"       True         This is max value
"infinity"            True         Same as inf
"infinityandBEYOND"   False        Extra characters wreck it
"12.34.56"            False        Only one dot allowed
u'四'                 False        Japanese '4' is not a float.
"#56"                 False        Pound sign
"56%"                 False        Percent of what?
"0E0"                 True         Exponential, move dot 0 places
0**0                  True         0___0  Exponentiation
"-5e-5"               True         Raise to a negative number
"+1e1"                True         Plus is OK with exponent
"+1e1^5"              False        Fancy exponent not interpreted
"+1e1.3"              False        No decimals in exponent
"-+1"                 False        Make up your mind
"(1)"                 False        Parenthesis is bad

你认为你知道什么是数字吗?你并没有想象中那么好!这并不是什么大惊小怪的事情。
不要在生命关键的软件上使用此代码!
以这种方式捕获广泛的异常,杀死canaries并吞噬异常会导致一个微小的机会,即一个有效的浮点数作为字符串将返回false。 float(...)代码行可能因与字符串内容无关的许多原因而失败。但是,如果你正在使用像Python这样的鸭子类型原型语言编写生命关键的软件,则会遇到更大的问题。

1
所以true变成了1,我想这是我从C++继承来的。 - FindOutIslamNow
9
我在2014年发布了这个答案。随着stackoverflow开发人员根据他们的微软工具堆栈改变字符编码方案,中文“4”的UTF-8字形已经多次转换。看到它在多年间翻盖是一件有趣的事情,因为新的转换方案也在不断确立其新的理念。但是,任何东方数字的UTF-8字形都不是Python浮点数。开个玩笑。 - Eric Leschinski
9
这怎么可能在如此广泛的例外情况下得到这么多点赞呢? - E.Serra
所有带有空格的内容都无法被转换,例如 "- 12.3""45 e6" - Simon
12
这个 except 子句应该仅限于 TypeErrorValueError - wim
显示剩余4条评论

579
def num(s):
    try:
        return int(s)
    except ValueError:
        return float(s)

90
隐式混合使用浮点数/整数可能会导致微妙的错误,因为在使用浮点数时可能会丢失精度,或者在浮点数/整数上执行“/”运算符时会得到不同的结果。根据上下文,最好返回整数或浮点数中的一个,而不是两者都有。 - jfs
15
@J.F.Sebastian 你说得完全正确,但有时候你想让输入来决定它将是哪一个。让输入来决定可以很好地配合鸭子类型。 - TimothyAWiseman
9
可以嵌套另一个try块,以在无法转换为浮点数时抛出异常。 - iBug
2
失败原因为s = u'\u0000' - Matt Hancock
1
@iBug 好主意!我建议在相应的 except 中抛出 ValueError :P - marcelm
@Matt 为什么不行呢?NUL 不是数字。如果您想将其转换为 0,则需要选择其他方法,例如 int(u'\x00'.encode('hex'), 16) - wjandrea

165
另外一个值得在这里提到的方法是ast.literal_eval

这可以用于安全地评估来自不可信源的包含Python表达式的字符串,而无需自己解析值。

也就是说,这是一个安全的'eval'方法。
>>> import ast
>>> ast.literal_eval("545.2222")
545.2222
>>> ast.literal_eval("31")
31

16
这并不是解决问题的好方法。在Python 2中它运行良好,但在Python 3中会出现以下情况:>>> import ast >>> ast.literal_eval('1-800-555-1212') -2566 >>>为了澄清这为什么是一个问题,如果你想让它保留电话号码而不假设它们是数学表达式,那么这种方法就不适用于你。 - royce3
6
是的,这是一个很好的观点,用户应该注意。修改行为最初是为了解决解析复杂字面量的一些问题。这在ast.literal_eval中可能是一个漏洞,并且已经在这里讨论过。 - wim
5
记录一下,ast在Python 3中不再将那个电话号码直接解析为-2566。这在Python 3.7的更新日志中有说明:_ast.literal_eval()变得更加严格。不再允许任意数字的加减。(由Serhiy Storchaka在bpo-31778中进行了贡献)_ - wim
注意:ast.literal_eval 似乎无法处理数字输入(会引发 ValueError: malformed node or string: 0)。 - mirekphd

87

本地化和逗号

在字符串表示数字的情况下,应该考虑逗号的可能性。例如float("545,545.2222")会抛出异常。相反,使用locale中的方法将字符串转换为数字并正确解释逗号。一旦设置了所需数字约定的语言环境,locale.atof方法就可以一步转换为浮点数。

示例1--美国数字约定

在美国和英国,逗号可用作千位分隔符。在这个美国语言环境的示例中,逗号被正确处理为分隔符:

>>> import locale
>>> a = u'545,545.2222'
>>> locale.setlocale(locale.LC_ALL, 'en_US.UTF-8')
'en_US.UTF-8'
>>> locale.atof(a)
545545.2222
>>> int(locale.atof(a))
545545
>>>

例子2 -- 欧洲数字约定

世界上大多数国家,逗号被用作小数点而不是句点。在这个以法语为语言环境的例子中,逗号被正确地处理为小数点:

>>> import locale
>>> b = u'545,2222'
>>> locale.setlocale(locale.LC_ALL, 'fr_FR')
'fr_FR'
>>> locale.atof(b)
545.2222

方法locale.atoi也可用,但参数应为整数。

当你知道一个浮点数或整数应该被返回时,这似乎是一个理想的解决方案,但是如果只有整数被传递,如何让它仅返回一个整数呢?例如,x = '1'; locale.atof(x) 返回 1.0,而我实际上想要的是 1 - user5359531
1
使用Dino的方法,我猜答案应该是使用类似这样的代码:locale.atof(x) if locale.localeconv().get('decimal_point') in x else locale.atoi(x) - user5359531
我建议使用Javier上面的方法(在try中包装locale.atoi并在异常时使用locale.atof - 这可能更易读)。 - Mark Chackerian
注意:locale.atof(my_int)会将类型从int更改为float... - mirekphd

83
float(x) if '.' in x else int(x)

63
吹毛求疵:无法处理像float("2e-3")这样的极端情况。 - Emile
27
注意:处理以字符串形式传递的货币金额时要小心,因为一些国家使用“,”作为小数分隔符。 - Ben G
139
@Emile:我不会把“2e-3”称为“极端情况”。这个答案是有问题的。 - jchl
15
不要将货币处理为浮点数,这样会引起麻烦。使用十进制来处理货币!(但是你关于“,”的评论仍然是有效且重要的) - ToolmakerSteve
6
不要忘记,“非数字”(NaN)和+/-无穷大也是有效的浮点数。因此,float("nan") 是一个完全有效的浮点数值,而上面的答案将无法捕获。 - Ronny Andersson
8
易被 IP 地址 192.168.0.1 破解;或者说“这不是一个好的方法。:)”。 - Todor Minakov

36

如果您不排斥使用第三方模块,可以查看fastnumbers模块。它提供了一个名为fast_real的函数,可以准确地执行这个问题所要求的操作,并且比纯Python实现更快:

>>> from fastnumbers import fast_real
>>> fast_real("545.2222")
545.2222
>>> type(fast_real("545.2222"))
float
>>> fast_real("31")
31
>>> type(fast_real("31"))
int

28
在Python中,我该如何解析数字字符串,例如"545.2222",以得到其对应的浮点数值542.2222?或将字符串"31"解析为整数31?
我只是想知道如何将浮点字符串解析为浮点数,以及(分别)将整数字符串解析为整数。
很好,你要求将它们分开处理。如果你混合使用它们,可能会给自己带来后续问题。简单的答案是:
"545.2222"转换为浮点数:
>>> float("545.2222")
545.2222

"31"转换为整数:

>>> int("31")
31

其他转换,整数与字符串及字面值之间的转换:

各种进制的转换,需要预先知道进制(默认为10)。注意可以在数字前面加上Python字面值所需的前缀(见下文)或者去掉前缀:

>>> int("0b11111", 2)
31
>>> int("11111", 2)
31
>>> int('0o37', 8)
31
>>> int('37', 8)
31
>>> int('0x1f', 16)
31
>>> int('1f', 16)
31

如果您事先不知道进制,但是您知道它们将具有正确的前缀,那么如果您将0作为进制传递,Python可以自动推断出进制。
>>> int("0b11111", 0)
31
>>> int('0o37', 0)
31
>>> int('0x1f', 0)
31

来自其他进制的非十进制(即整数)字面量

如果您的动机是让您自己的代码清晰地表示硬编码的特定值,那么您可能不需要从基数进行转换 - 您可以使用正确的语法让Python自动为您完成。

您可以使用适当的前缀来获得自动转换为整数的以下文字。这些对于Python 2和3都有效:

二进制,前缀0b

>>> 0b11111
31

八进制,前缀0o

>>> 0o37
31

十六进制,前缀0x
>>> 0x1f
31

这在描述二进制标志、代码中的文件权限或十六进制颜色值时非常有用-例如,注意不要加引号:
>>> 0b10101 # binary flags
21
>>> 0o755 # read, write, execute perms for owner, read & ex for group & others
493
>>> 0xffffff # the color, white, max values for red, green, and blue
16777215

使Python 2中的含糊不清的八进制与Python 3兼容

如果您在Python 2中看到以0开头的整数,则这是(已弃用的)八进制语法。

>>> 037
31

这是不好的,因为看起来值应该为37。因此在Python 3中,它现在会引发一个SyntaxError

>>> 037
  File "<stdin>", line 1
    037
      ^
SyntaxError: invalid token

使用0o前缀将Python 2的八进制转换为在2和3中都可用的八进制:

>>> 0o37
31

27

用户codelogicharley是正确的,但要记住,如果您知道字符串是整数(例如545),则可以在不先转换为浮点数的情况下调用int("545")。

如果您的字符串在列表中,则也可以使用map函数。

>>> x = ["545.0", "545.6", "999.2"]
>>> map(float, x)
[545.0, 545.60000000000002, 999.20000000000005]
>>>

只有当它们都是相同类型时才是好的。


22

这个问题似乎有点老了。但是让我建议一个名为parseStr的函数,它可以做类似的事情,即返回整数或浮点数,如果给定的ASCII字符串无法转换为它们中的任何一个,则原样返回。当然,代码可能需要调整以仅执行您想要的操作:

   >>> import string
   >>> parseStr = lambda x: x.isalpha() and x or x.isdigit() and \
   ...                      int(x) or x.isalnum() and x or \
   ...                      len(set(string.punctuation).intersection(x)) == 1 and \
   ...                      x.count('.') == 1 and float(x) or x
   >>> parseStr('123')
   123
   >>> parseStr('123.3')
   123.3
   >>> parseStr('3HC1')
   '3HC1'
   >>> parseStr('12.e5')
   1200000.0
   >>> parseStr('12$5')
   '12$5'
   >>> parseStr('12.2.2')
   '12.2.2'

12
“1e3”是Python中的一个数字,但根据您的代码它是一个字符串。 - Cees Timmerman
我更喜欢这个答案。 - enchance

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接