Python:检查一个string是否代表int,而不使用Try / Except?

有没有什么办法来判断一个string是否代表一个整数(例如'3''-17'而不是'3.14''asfasfas' )而不使用try / except机制?

 is_int('3.14') = False is_int('-7') = True 

如果你真的只是使用try/except s try/except的所有地方感到恼火,请写一个帮助函数:

 def RepresentsInt(s): try: int(s) return True except ValueError: return False >>> print RepresentsInt("+123") True >>> print RepresentsInt("10.0") False 

这将是更多的代码来覆盖Python认为是整数的所有string。 我说这个只是pythonic。

用正整数你可以使用.isdigit

 >>> '16'.isdigit() True 

尽pipe如此,它不适用于负整数。 假设您可以尝试以下操作:

 >>> s = '-17' >>> s.startswith('-') and s[1:].isdigit() True 

它将不能以“ '16.0'格式工作,这在这个意义上类似于int casting。

编辑

 def check_int(s): if s[0] in ('-', '+'): return s[1:].isdigit() return s.isdigit() 

你知道,我已经发现(而且我已经反复testing过),除了不pipe什么原因都不能很好地执行。 我经常尝试几种做事情的方法,我不认为我曾经发现过使用try /除了执行最好的那些testing的方法,实际上在我看来,这些方法通常是靠近最糟糕的,如果不是最糟糕的。 不是在每一种情况下,而是在许多情况下。 我知道很多人都说这是“Pythonic”的方式,但这是我与他们分道扬</s>的一个领域。 对我来说,它既不是非常高效,也不是非常优雅,所以我倾向于只用它来进行错误捕获和报告。

我会抱怨说,PHP,Perl,ruby,C,甚至是吓人的shell都有简单的函数来testing整数引擎的string,但是在validation这些假设时的尽职调查却让我失望了! 显然这种缺乏是一种常见的疾病。

这里是Richard的post的一个快速和肮脏的编辑:

 import sys, time, re g_intRegex = re.compile(r"[-+]?\d+(\.0*)?$") testvals = [ # integers 0, 1, -1, 1.0, -1.0, '0', '0.','0.0', '1', '-1', '+1', '1.0', '-1.0', '+1.0', '06', # non-integers 1.1, -1.1, '1.1', '-1.1', '+1.1', '1.1.1', '1.1.0', '1.0.1', '1.0.0', '1.0.', '1..0', '1..', '0.0.', '0..0', '0..', 'one', object(), (1,2,3), [1,2,3], {'one':'two'}, # with spaces ' 0 ', ' 0.', ' .0','.01 ' ] def isInt_try(v): try: i = int(v) except: return False return True def isInt_str(v): v = str(v).strip() return v=='0' or (v if v.find('..') > -1 else v.lstrip('-+').rstrip('0').rstrip('.')).isdigit() def isInt_re(v): import re if not hasattr(isInt_re, 'intRegex'): isInt_re.intRegex = re.compile(r"[-+]?\d+(\.0*)?$") return isInt_re.intRegex.match(str(v).strip()) is not None def isInt_re2(v): return g_intRegex.match(str(v).strip()) is not None def timeFunc(func, times): t1 = time.time() for n in xrange(times): for v in testvals: r = func(v) t2 = time.time() return t2 - t1 def testFuncs(funcs): for func in funcs: sys.stdout.write( "\t%s\t|" % func.__name__) print for v in testvals: sys.stdout.write("%s" % str(v)) for func in funcs: sys.stdout.write( "\t\t%s\t|" % func(v)) print if __name__ == '__main__': print print "tests.." testFuncs((isInt_try, isInt_str, isInt_re, isInt_re2)) print print "timings.." print "isInt_try: %6.4f" % timeFunc(isInt_try, 10000) print "isInt_str: %6.4f" % timeFunc(isInt_str, 10000) print "isInt_re: %6.4f" % timeFunc(isInt_re, 10000) print "isInt_re2: %6.4f" % timeFunc(isInt_re2, 10000) 

以下是输出的有趣部分:

 timings.. isInt_try: 1.2454 isInt_str: 0.7878 isInt_re: 1.5731 isInt_re2: 0.8087 

正如你所看到的,string方法是最快的。 它几乎是正则expression式方法的两倍,它避免依赖任何全局variables,比try:except方法快一半以上。 依赖于某些全局variables(或者模块属性)的正则expression式方法是紧随其后的。

我想到这些,我的select是

 isInt = isInt_str 

但呃..这是复制和复制和重新复制整个string! (而且它是最快的方法!?)AC方法可以扫描一遍,完成。 交stream方法扫描string一次将是正确的事情,我想? 我想可能会有一些string编码问题需要处理..无论如何,我会尝试现在工作一个,但我没有这个时间。 =(也许我以后会回来的。

使用正则expression式:

 import re def RepresentsInt(s): return re.match(r"[-+]?\d+$", s) is not None 

如果您还必须接受小数部分:

 def RepresentsInt(s): return re.match(r"[-+]?\d+(\.0*)?$", s) is not None 

如果您经常这样做,为了提高性能,请使用re.compile()仅编译一次正则expression式。

正确的RegEx解决scheme将结合Greg Hewgill和Nowell的想法,但不能使用全局variables。 您可以通过将属性附加到方法来完成此操作。 另外,我知道把import放在方法中是不被接受的,但是我要做的是一个“懒惰的模块”效果,比如http://peak.telecommunity.com/DevCenter/Importing#lazy-imports

编辑:到目前为止,我最喜欢的技术是使用String对象的唯一方法。

 #!/usr/bin/env python # Uses exclusively methods of the String object def isInteger(i): i = str(i) return i=='0' or (i if i.find('..') > -1 else i.lstrip('-+').rstrip('0').rstrip('.')).isdigit() # Uses re module for regex def isIntegre(i): import re if not hasattr(isIntegre, '_re'): print "I compile only once. Remove this line when you are confident in that." isIntegre._re = re.compile(r"[-+]?\d+(\.0*)?$") return isIntegre._re.match(str(i)) is not None # When executed directly run Unit Tests if __name__ == '__main__': for o in [ # integers 0, 1, -1, 1.0, -1.0, '0', '0.','0.0', '1', '-1', '+1', '1.0', '-1.0', '+1.0', # non-integers 1.1, -1.1, '1.1', '-1.1', '+1.1', '1.1.1', '1.1.0', '1.0.1', '1.0.0', '1.0.', '1..0', '1..', '0.0.', '0..0', '0..', 'one', object(), (1,2,3), [1,2,3], {'one':'two'} ]: # Notice the integre uses 're' (intended to be humorous) integer = ('an integer' if isInteger(o) else 'NOT an integer') integre = ('an integre' if isIntegre(o) else 'NOT an integre') if isinstance(o, str): o = ("'%s'" % (o,)) print "%30s is %14s is %14s" % (o, integer, integre) 

对于class级中不太冒险的成员来说,这里是输出:

 I compile only once. Remove this line when you are confident in that. 0 is an integer is an integre 1 is an integer is an integre -1 is an integer is an integre 1.0 is an integer is an integre -1.0 is an integer is an integre '0' is an integer is an integre '0.' is an integer is an integre '0.0' is an integer is an integre '1' is an integer is an integre '-1' is an integer is an integre '+1' is an integer is an integre '1.0' is an integer is an integre '-1.0' is an integer is an integre '+1.0' is an integer is an integre 1.1 is NOT an integer is NOT an integre -1.1 is NOT an integer is NOT an integre '1.1' is NOT an integer is NOT an integre '-1.1' is NOT an integer is NOT an integre '+1.1' is NOT an integer is NOT an integre '1.1.1' is NOT an integer is NOT an integre '1.1.0' is NOT an integer is NOT an integre '1.0.1' is NOT an integer is NOT an integre '1.0.0' is NOT an integer is NOT an integre '1.0.' is NOT an integer is NOT an integre '1..0' is NOT an integer is NOT an integre '1..' is NOT an integer is NOT an integre '0.0.' is NOT an integer is NOT an integre '0..0' is NOT an integer is NOT an integre '0..' is NOT an integer is NOT an integre 'one' is NOT an integer is NOT an integre <object object at 0x103b7d0a0> is NOT an integer is NOT an integre (1, 2, 3) is NOT an integer is NOT an integre [1, 2, 3] is NOT an integer is NOT an integre {'one': 'two'} is NOT an integer is NOT an integre 

Greg Hewgill的方法是缺less了一些组件:主要的“^”只匹配string的开始,并且事先编译。 但是这种方法可以让你避免一个尝试:exept:

 import re INT_RE = re.compile(r"^[-]?\d+$") def RepresentsInt(s): return INT_RE.match(str(s)) is not None 

我会感兴趣为什么你试图避免尝试:除了?

 >>> "+7".lstrip("-+").isdigit() True >>> "-7".lstrip("-+").isdigit() True >>> "7".lstrip("-+").isdigit() True >>> "13.4".lstrip("-+").isdigit() False 

所以你的function是:

 def is_int(val): return val[1].isdigit() and val.lstrip("-+").isdigit() 

我认为

 s.startswith('-') and s[1:].isdigit() 

最好重写为:

 s.replace('-', '').isdigit() 

因为s [1:]也创build一个新的string

但更好的解决scheme是

 s.lstrip('+-').isdigit() 

在我看来,这可能是最直接和最pythonic的方法。 我没有看到这个解决scheme,它基本上是一样的正则expression式,但没有正则expression式。

 def is_int(test): import string return not (set(test) - set(string.digits)) 

这是一个函数,parsing没有提出错误。 它处理明显的情况返回None故障(在CPython上默认处理最多2000' – / +'符号!):

 #!/usr/bin/env python def get_int(number): splits = number.split('.') if len(splits) > 2: # too many splits return None if len(splits) == 2 and splits[1]: # handle decimal part recursively :-) if get_int(splits[1]) != 0: return None int_part = splits[0].lstrip("+") if int_part.startswith('-'): # handle minus sign recursively :-) return get_int(int_part[1:]) * -1 # successful 'and' returns last truth-y value (cast is always valid) return int_part.isdigit() and int(int_part) 

一些testing:

 tests = ["0", "0.0", "0.1", "1", "1.1", "1.0", "-1", "-1.1", "-1.0", "-0", "--0", "---3", '.3', '--3.', "+13", "+-1.00", "--+123", "-0.000"] for t in tests: print "get_int(%s) = %s" % (t, get_int(str(t))) 

结果:

 get_int(0) = 0 get_int(0.0) = 0 get_int(0.1) = None get_int(1) = 1 get_int(1.1) = None get_int(1.0) = 1 get_int(-1) = -1 get_int(-1.1) = None get_int(-1.0) = -1 get_int(-0) = 0 get_int(--0) = 0 get_int(---3) = -3 get_int(.3) = None get_int(--3.) = 3 get_int(+13) = 13 get_int(+-1.00) = -1 get_int(--+123) = 123 get_int(-0.000) = 0 

为了您的需要,您可以使用:

 def int_predicate(number): return get_int(number) is not None 

我有一种可能性,根本不使用int,除非string不代表数字,否则不应该引发exception

 float(number)==float(number)//1 

它应该适用于任何types的string浮动接受,积极,消极,工程符号…

呃..试试这个:

 def int_check(a): if int(a) == a: return True else: return False 

如果你不放置一个不是数字的string,这将起作用。

还有(我忘了把数字检查部分),有一个函数检查string是否是一个数字。 这是str.isdigit()。 这是一个例子:

 a = 2 a.isdigit() 

如果你调用a.isdigit(),它将返回True。