如何检查一个string是否是一个数字(浮点数)?
什么是最好的方法来检查一个string是否可以在Python中表示为一个数字?
我现在有的function是:
def is_number(s): try: float(s) return True except ValueError: return False
这不仅丑陋而且缓慢,看起来笨重。 但是我还没有find更好的方法,因为在主函数中调用float
更糟糕。
其中,不仅是丑陋而且缓慢
我会争执两个。
正则expression式或其他stringparsing会更加丑陋和慢。
我不确定有什么比以上更快。 它调用函数并返回。 Try / Catch不会引入太多开销,因为最常见的exception是在没有大量的堆栈search的情况下被捕获的。
问题是任何数值转换函数都有两种结果
- 一个数字,如果数字是有效的
- 状态码(例如,通过errno)或例外,以显示没有有效的号码可以被parsing。
C(作为一个例子)围绕着这个方法。 Python清楚而明确地阐述了它。
我认为你的代码是完美的。
如果你正在寻找parsing(正,无符号)整数,而不是浮动,你可以使用string对象的isdigit()
函数。
>>> a = "03523" >>> a.isdigit() True >>> b = "963spam" >>> b.isdigit() False
string方法 – isdigit()
还有一些Unicodestring,我不太熟悉Unicode – 十进制/十进制
有一个例外,你可能要考虑到:string“NaN”
如果你希望is_number为NaN返回FALSE,那么这个代码就不会工作,因为Python把它转换成了一个不是数字的数字表示(谈论身份问题):
>>> float('NaN') nan
否则,我应该真的感谢你现在广泛使用的那段代码。 🙂
G。
这个怎么样:
'3.14'.replace('.','',1).isdigit()
只有当有一个或者没有'。'时才会返回true。 在数字串中。
'3.14.5'.replace('.','',1).isdigit()
将返回false
编辑:刚刚看到另一个评论…添加.replace(badstuff,'',maxnum_badstuff)
为其他情况下可以完成。 如果你通过盐而不是任意的调味品(ref: xkcd#974 ),这将做罚款:P
在Alfe指出你不需要单独检查float作为复杂句柄的时候更新:
def is_number(s): try: complex(s) # for int, long, float and complex except ValueError: return False return True
先前说过:在一些罕见的情况下,您可能还需要检查复数(例如1 + 2i),这不能用浮点数表示:
def is_number(s): try: float(s) # for int, long and float except ValueError: try: complex(s) # for complex except ValueError: return False return True
这不仅丑陋而且缓慢,看起来笨重。
这可能需要一些习惯,但这是这样做的pythonic方式。 正如已经指出的那样,替代品更糟。 但是这样做还有另一个好处:多态。
鸭子打字的核心思想是“如果它像鸭子一样走路说话,那么它就是一只鸭子。” 如果您决定需要对string进行子类化,那么您可以更改如何确定某个东西是否可以转换为浮点数? 或者如果你决定完全testing一些其他的对象呢? 你可以做这些事情,而不必改变上面的代码。
其他语言通过使用接口来解决这些问题。 我将保存哪个解决scheme对另一个线程更好的分析。 不过,python肯定是在鸭子打字方面,如果你打算在Python中进行大量的编程,你可能不得不习惯这样的语法(但是这并不意味着你当然要喜欢它)。
另一件你可能要考虑的事情是:与许多其他语言相比,Python在抛出和捕获exception方面速度相当快(比.Net快30倍)。 哎呀,语言本身甚至会抛出exception来传达非常规的正常编程条件(每次使用for循环时)。 因此,我不会太担心这个代码的性能方面,直到你注意到一个重大的问题。
TL; DR最好的解决scheme是s.replace('.','',1).isdigit()
我做了一些比较不同方法的基准
def is_number_tryexcept(s): """ Returns True is string is a number. """ try: float(s) return True except ValueError: return False import re def is_number_regex(s): """ Returns True is string is a number. """ if re.match("^\d+?\.\d+?$", s) is None: return s.isdigit() return True def is_number_repl_isdigit(s): """ Returns True is string is a number. """ return s.replace('.','',1).isdigit()
如果string不是一个数字,那么except-block非常慢。 但更重要的是,try-except方法是正确处理科学符号的唯一方法。
funcs = [ is_number_tryexcept, is_number_regex, is_number_repl_isdigit ] a_float = '.1234' print('Float notation ".1234" is not supported by:') for f in funcs: if not f(a_float): print('\t -', f.__name__)
浮点表示法“.1234”不支持:
– is_number_regex
scientific1 = '1.000000e+50' scientific2 = '1e50' print('Scientific notation "1.000000e+50" is not supported by:') for f in funcs: if not f(scientific1): print('\t -', f.__name__) print('Scientific notation "1e50" is not supported by:') for f in funcs: if not f(scientific2): print('\t -', f.__name__)
科学记数法“1.000000e + 50”不支持:
– is_number_regex
– is_number_repl_isdigit
科学记数法“1e50”不支持:
– is_number_regex
– is_number_repl_isdigit
编辑:基准testing结果
import timeit test_cases = ['1.12345', '1.12.345', 'abc12345', '12345'] times_n = {f.__name__:[] for f in funcs} for t in test_cases: for f in funcs: f = f.__name__ times_n[f].append(min(timeit.Timer('%s(t)' %f, 'from __main__ import %s, t' %f) .repeat(repeat=3, number=1000000)))
以下function进行了testing
from re import match as re_match from re import compile as re_compile def is_number_tryexcept(s): """ Returns True is string is a number. """ try: float(s) return True except ValueError: return False def is_number_regex(s): """ Returns True is string is a number. """ if re_match("^\d+?\.\d+?$", s) is None: return s.isdigit() return True comp = re_compile("^\d+?\.\d+?$") def compiled_regex(s): """ Returns True is string is a number. """ if comp.match(s) is None: return s.isdigit() return True def is_number_repl_isdigit(s): """ Returns True is string is a number. """ return s.replace('.','',1).isdigit()
对于int
使用这个:
>>> "1221323".isdigit() True
但是对于float
我们需要一些技巧;-)。 每个浮点数有一个点…
>>> "12.34".isdigit() False >>> "12.34".replace('.','',1).isdigit() True >>> "12.3.4".replace('.','',1).isdigit() False
对于负数也只需添加lstrip()
:
>>> '-12'.lstrip('-') '12'
现在我们得到一个普遍的方式:
>>> '-12.34'.lstrip('-').replace('.','',1).isdigit() True >>> '.-234'.lstrip('-').replace('.','',1).isdigit() False
只是模仿C#
在C#中有两个不同的函数来处理标量值的parsing:
- Float.Parse()
- Float.TryParse()
float.parse():
def parse(string): try: return float(string) except Exception: throw TypeError
注意:如果您想知道为什么我将exception更改为TypeError,那么这里是文档 。
float.try_parse():
def try_parse(string, fail=None): try: return float(string) except Exception: return fail;
注意:你不想返回布尔值“False”,因为它仍然是一个值types。 没有更好的,因为它表明失败。 当然,如果你想要不同的东西,你可以把失败参数改成你想要的。
为了扩展float以包含'parse()'和'try_parse()',你需要monkeypatch'float'类来添加这些方法。
如果你想尊重预先存在的function,代码应该是这样的:
def monkey_patch(): if(!hasattr(float, 'parse')): float.parse = parse if(!hasattr(float, 'try_parse')): float.try_parse = try_parse
SideNote:我个人比较喜欢把它叫做Monkey Punching,因为当我这样做的时候感觉就像是在滥用语言,但是YMMV。
用法:
float.parse('giggity') // throws TypeException float.parse('54.3') // returns the scalar value 54.3 float.tryParse('twank') // returns None float.tryParse('32.2') // returns the scalar value 32.2
而耆英耆那教徒对罗马教廷说:“任何你能做的我都可以做得更好,我可以做得比你更好。”
我知道这是特别老,但我会添加一个答案,我相信涵盖了从最高的投票答案中缺less的信息,可能是非常有价值的任何谁发现这一点:
对于以下每种方法,如果需要接受任何input,请将它们连接在一起。 (假设我们使用整数的声音定义而不是0-255等)
x.isdigit()
适用于检查x是否为整数。
x.replace('-','').isdigit()
适用于检查x是否定的。(Check in in first position)
x.replace('.','').isdigit()
适用于检查x是否为小数。
x.replace(':','').isdigit()
适用于检查x是否是比率。
x.replace('/','',1).isdigit()
适用于检查x是否是分数。
对于非数字string,请try: except:
实际上比正则expression式慢。 对于有效数字的string,正则expression式更慢。 所以,适当的方法取决于你的input。
如果您发现自己处于性能绑定中,则可以使用名为fastnumbers的新第三方模块,该模块提供了一个名为isfloat的函数。 充分披露,我是作者。 我已经把结果列入下面的时间表。
from __future__ import print_function import timeit prep_base = '''\ x = 'invalid' y = '5402' z = '4.754e3' ''' prep_try_method = '''\ def is_number_try(val): try: float(val) return True except ValueError: return False ''' prep_re_method = '''\ import re float_match = re.compile(r'[-+]?\d*\.?\d+(?:[eE][-+]?\d+)?$').match def is_number_re(val): return bool(float_match(val)) ''' fn_method = '''\ from fastnumbers import isfloat ''' print('Try with non-number strings', timeit.timeit('is_number_try(x)', prep_base + prep_try_method), 'seconds') print('Try with integer strings', timeit.timeit('is_number_try(y)', prep_base + prep_try_method), 'seconds') print('Try with float strings', timeit.timeit('is_number_try(z)', prep_base + prep_try_method), 'seconds') print() print('Regex with non-number strings', timeit.timeit('is_number_re(x)', prep_base + prep_re_method), 'seconds') print('Regex with integer strings', timeit.timeit('is_number_re(y)', prep_base + prep_re_method), 'seconds') print('Regex with float strings', timeit.timeit('is_number_re(z)', prep_base + prep_re_method), 'seconds') print() print('fastnumbers with non-number strings', timeit.timeit('isfloat(x)', prep_base + 'from fastnumbers import isfloat'), 'seconds') print('fastnumbers with integer strings', timeit.timeit('isfloat(y)', prep_base + 'from fastnumbers import isfloat'), 'seconds') print('fastnumbers with float strings', timeit.timeit('isfloat(z)', prep_base + 'from fastnumbers import isfloat'), 'seconds') print()
Try with non-number strings 2.39108395576 seconds Try with integer strings 0.375686168671 seconds Try with float strings 0.369210958481 seconds Regex with non-number strings 0.748660802841 seconds Regex with integer strings 1.02021503448 seconds Regex with float strings 1.08564686775 seconds fastnumbers with non-number strings 0.174362897873 seconds fastnumbers with integer strings 0.179651021957 seconds fastnumbers with float strings 0.20222902298 seconds
如你看到的
-
try: except:
对于数字input是快速的,但对于无效input非常慢 - 当input无效时,正则expression式非常有效
- 在两种情况下,
fastnumbers
胜出
你可以使用Unicodestring,他们有一个方法来做你想要的:
>>> s = u"345" >>> s.isnumeric() True
要么:
>>> s = "345" >>> u = unicode(s) >>> u.isnumeric() True
浮动和捕获ValueError可能是最快的方法,因为float()专为此而devise。 任何需要stringparsing(正则expression式等)的东西可能会比较慢,因为它没有被调整为这个操作。 我的$ 0.02。
比方说你有string中的数字。 str =“100949”,你想检查它是否只有数字
if str.isdigit(): returns TRUE or FALSE
isdigit文档
否则你的方法很好地发现string中数字的出现。
所以把它放在一起,检查Nan,无穷大和复数(看起来它们是用j指定的,而不是i,即1 + 2j),结果是:
def is_number(s): try: n=str(float(s)) if n == "nan" or n=="inf" or n=="-inf" : return False except ValueError: try: complex(s) # for complex except ValueError: return False return True
你的代码对我来说看起来很好。
也许你认为代码是“笨重的”,因为使用exception? 请注意,由于Python性能低下,Python程序员倾向于大量使用exception来提高代码的可读性。
我想看看哪种方法最快,而且发现exception是最快的。
import time import re check_regexp = re.compile("^\d*\.?\d*$") check_replace = lambda x: x.replace('.','',1).isdigit() numbers = [str(float(x) / 100) for x in xrange(10000000)] def is_number(s): try: float(s) return True except ValueError: return False start = time.time() b = [is_number(x) for x in numbers] print time.time() - start # returns 4.10500001907 start = time.time() b = [check_regexp.match(x) for x in numbers] print time.time() - start # returns 5.41799998283 start = time.time() b = [check_replace(x) for x in numbers] print time.time() - start # returns 4.5110001564
我做了一些速度testing。 比方说,如果string可能是一个数字的尝试/除了策略是最快possible.Ifstring不可能是一个数字,你有兴趣整数检查,值得做一些testing(isdigit加标题' – ')。 如果您有兴趣检查浮点数,则必须使用try / except代码。
RyanNbuild议
如果你想返回一个NaN和Inf的False,把行改为x = float(s); 返回(x == x)和(x-1!= x)。 对于除Inf和NaN之外的所有浮标,这应该返回True
但是这并不奏效,因为对于足够大的浮点数, x-1 == x
返回true。 例如, 2.0**54 - 1 == 2.0**54
如果你想知道整个string是否可以表示为一个数字,你会想要使用一个正则expression式(或者可能将浮点数转换回string并将其与源string进行比较,但是我猜这不是很快)。
这是我做这个简单的方法。 假设我正在循环一些string,如果它们是数字,我想将它们添加到数组中。
try: myvar.append( float(string_to_check) ) except: continue
将myvar.apppendreplace为你想对string进行的任何操作,如果它是一个数字。 我们的想法是尝试使用float()操作并使用返回的错误来确定string是否是数字。
我需要确定一个string转换为基本types(float,int,str,bool)。 在互联网上找不到任何东西之后,我创build了这个:
def str_to_type (s): """ Get possible cast type for a string Parameters ---------- s : string Returns ------- float,int,str,bool : type Depending on what it can be cast to """ try: f = float(s) if "." not in s: return int return float except ValueError: value = s.upper() if value == "TRUE" or value == "FALSE": return bool return type(s)
例
str_to_type("true") # bool str_to_type("6.0") # float str_to_type("6") # int str_to_type("6abc") # str str_to_type(u"6abc") # unicode
您可以捕获该types并使用它
s = "6.0" type_ = str_to_type(s) # float f = type_(s)
尝试这个。
def is_number(var): try: if var == int(var): return True except Exception: return False
我也使用了你提到的function,但很快我注意到string为“南”,“Inf”,它的变化被认为是数字。 所以我build议你改进你的函数的版本,这将在这些types的input上返回false,并且不会失败“1e3”变体:
def is_float(text): try: float(text) # check for nan/infinity etc. if text.isalpha(): return False return True except ValueError: return False
您可以通过返回比True和False更有用的值来以有用的方式概括exception技术。 例如,这个函数把引号放在string中,但是只保留数字。 这正是我所需要的一个快速而脏的filter,为R做了一些variables定义。
import sys def fix_quotes(s): try: float(s) return s except ValueError: return '"{0}"'.format(s) for line in sys.stdin: input = line.split() print input[0], '<- c(', ','.join(fix_quotes(c) for c in input[1:]), ')'
我正在研究一个问题,使我对这个线程有所了解,即如何以最直观的方式将数据集合转换为string和数字。 我在阅读原始代码后意识到,我需要的是两种不同的方式:
1 – 如果string表示一个整数,我想要一个整数结果
2 – 我想要一个数字或string结果来坚持一个数据结构
所以我调整了原来的代码来产生这个派生:
def string_or_number(s): try: z = int(s) return z except ValueError: try: z = float(s) return z except ValueError: return s
你可以使用正则expression式。
number = raw_input("Enter a number: ") if re.match(r'^\d+$', number): print "It's integer" print int(number) elif re.match(r'^\d+\.\d+$', number): print "It's float" print float(number) else: print("Please enter a number")
使用以下它处理所有情况: –
import re a=re.match('((\d+[\.]\d*$)|(\.)\d+$)' , '2.3') a=re.match('((\d+[\.]\d*$)|(\.)\d+$)' , '2.') a=re.match('((\d+[\.]\d*$)|(\.)\d+$)' , '.3') a=re.match('((\d+[\.]\d*$)|(\.)\d+$)' , '2.3sd') a=re.match('((\d+[\.]\d*$)|(\.)\d+$)' , '2.3')
要检查input值是否为float
,可以将inputtypes与float
进行比较
def isFloat(s): realFloat = 0.1 if type(s) == type(realFloat): return True else: return False
返回:
False # s = 5 True # s = 1.2345
原来的post实际上会在s = 5
返回True
,因为它是一个数字(整数),你可以将一个int
成一个没有ValueError
的float
。 如果您试图validation这是实际的float
而不是一个数字,您将需要考虑这种情况。