![](/img/trans.png)
[英]Fast checking if a string can be converted to float or int in python
[英]Checking if a string can be converted to float in Python
我有一些 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 块中,看看它是否成功,如本问题所述。
有人有其他想法吗? 关于分区和 try/catch 方法的相对优点的意见?
我只会用..
try:
float(element)
except ValueError:
print "Not a float"
..这很简单,而且有效。 请注意,如果元素是例如 1<<1024,它仍然会抛出 OverflowError。
另一种选择是正则表达式:
import re
if re.match(r'^-?\d+(?:\.\d+)$', element) is None:
print "Not float"
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
'1.43'.replace('.','',1).isdigit()
仅当有一个或没有“。”时才会返回true
。 在数字串中。
'1.4.3'.replace('.','',1).isdigit()
将返回false
'1.ww'.replace('.','',1).isdigit()
将返回false
TL;博士:
try: except:
方法是最好的原生 Python 方法。 通过名为fastnumbers的第三方模块还有另一种方法可用(披露,我是作者); 它提供了一个名为isfloat的函数。 我在这个答案中采用了 Jacob Gabrielson 概述的 unittest 示例,但添加了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
方法是相当不错的。
只是为了多样化,这是另一种方法。
>>> 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
函数is_digit(str)
的简化版本,在大多数情况下就足够了(不考虑指数符号和“NaN”值):
def is_digit(str):
return str.lstrip('-').replace('.', '').isdigit()
如果您关心性能(我不建议您这样做),那么基于尝试的方法显然是赢家(与基于分区的方法或正则表达式方法相比),只要您不期望很多无效字符串,在这种情况下它可能会变慢(可能是由于异常处理的成本)。
再说一次,我不是建议你关心性能,只是给你数据,以防你每秒执行 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,正则表达式取自 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()
如果您不需要担心数字的科学或其他表达式,并且只使用可能是带句点或不带句点的数字的字符串:
功能
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。
此正则表达式将检查科学浮点数:
^[-+]?(?:\b[0-9]+(?:\.[0-9]*)?|\.[0-9]+\b)(?:[eE][-+]?[0-9]+\b)?$
但是,我相信您最好的选择是尝试使用解析器。
我使用了已经提到的函数,但很快我注意到字符串为“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
- except
- else
子句,这将捕获当传递的值无法转换为浮点数时引发的任何转换/值错误
def try_parse_float(item):
result = None
try:
float(item)
except:
pass
else:
result = float(item)
return result
一个简单的函数,无需尝试和除操作即可获得数字类型
def number_type(number):
if number.isdigit():
return int(number)
elif number.replace(".","").isdigit():
return float(number)
else:
return(type(number))
我一直在寻找一些类似的代码,但看起来使用 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: ")
尝试转换为浮动。 如果有错误,打印 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'
将字典作为参数传递,它将转换可以转换为浮点数的字符串并保留其他字符串
def covertDict_float(data):
for i in data:
if data[i].split(".")[0].isdigit():
try:
data[i] = float(data[i])
except:
continue
return data
我尝试了上面一些简单的选项,围绕转换为浮点数进行了尝试测试,发现大多数回复都存在问题。
简单测试(按照上述答案):
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
似乎很多正则表达式都会错过一件事或另一件事。 到目前为止,这一直对我有用:
(?i)^\s*[+-]?(?:inf(inity)?|nan|(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?)\s*$
它允许带有符号、nan、小数点前没有数字和前导/尾随空格(如果需要)的无穷大(或 inf)。 需要^
和$
以防止将1.2f-2
部分匹配为1.2
。
如果您需要解析一些将D
用于双精度科学记数法的文件,则可以使用[ed]
而不是仅使用e
。 您可能想在之后替换它,或者只是在检查之前替换它们,因为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]
我已经编写了自己的函数。 我使用 floatN() 或 floatZ() 而不是 float(value)。 如果不能将值转换为浮点数,则返回 None 或 0.0。 我将它们保存在我称为 safeCast 的模块中。
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
中的最后一个值包含小数位的假设。
您可以创建一个函数 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')
我们可以将正则表达式用作: import re if re.match('[0-9]*.?[0-9]+', <your_string>): print("Its a float/int") else: print("Its something alien")
让我用英语解释正则表达式,
现在,让我们转换
str(strval).isdigit()
似乎很简单。
处理存储为字符串或 int 或 float 的值
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.