ChatGPT解决这个技术问题 Extra ChatGPT

如何在不使用 try/except 的情况下检查字符串是否表示 int?

有没有办法在不使用 try/except 机制的情况下判断 string 是否表示整数(例如,'3''-17' 但不是 '3.14''asfasfas')?

is_int('3.14') == False
is_int('-7')   == True
为什么两者都试图“以艰难的方式”做到这一点? try/except 有什么问题?
是的,try/except 有什么问题?请求宽恕比请求许可要好。
我会问为什么这个简单的事情需要try/except?异常系统是一头复杂的野兽,但这是一个简单的问题。
@Aivar 停止传播 FUD。单个 try/except 块甚至不会接近“复杂”。
不过,这并不是真正的 FUD。您将有效地编写 4 行代码,期望发生某些事情,捕获该异常并执行您的默认设置,而不是使用单行代码。

S
SilentGhost

对于正整数,您可以使用 .isdigit

>>> '16'.isdigit()
True

但它不适用于负整数。假设您可以尝试以下操作:

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

它不适用于 '16.0' 格式,这在这个意义上类似于 int 强制转换。

编辑:

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

如果没有其他特殊情况,这将无法处理“+17”。
您必须测试两种情况: lambda s: s.isdigit() 或 (s.startswith('-') 和 s[1:].isdigit())
@Roberto:当然应该!我相信你有能力这样做!
注意:u'²'.isdigit() 为真,但 int(u'²') 引发 ValueError。请改用 u.isdecimal()str.isdigit() 依赖于 Python 2 的语言环境。
check_int('') 将引发异常而不是返回 False
K
Kenan Banks

如果您真的对到处使用 try/except 感到厌烦,请编写一个辅助函数:

def RepresentsInt(s):
    try: 
        int(s)
        return True
    except ValueError:
        return False

>>> print RepresentsInt("+123")
True
>>> print RepresentsInt("10.0")
False

这将是更多的代码来准确覆盖 Python 认为整数的所有字符串。我说这只是pythonic。


那么用复杂机制解决简单问题是pythonic吗?有一种用于检测 int 写入函数“int”内部的算法——我不明白为什么它不作为布尔函数公开。
@Aivar:这 5 行函数不是一个复杂的机制。
除了:>>> print RepresentsInt(10.0) True >>> print RepresentsInt(10.06) True
我不知道为什么这是公认的答案或有如此多的赞成票,因为这与 OP 所要求的完全相反。
问题包含:“不使用 try/except 机制?”。不满足该要求,因为使用了 try/except(即使包装在 func 中)。
T
Tiago Martins Peres

你知道,我发现(并且我已经反复测试过)无论出于何种原因,try/except 的性能都不是很好。我经常尝试几种做事的方法,但我认为我从未找到使用 try/except 来执行测试中最好的方法,事实上在我看来这些方法通常接近最坏的,如果不是最坏的。并非在所有情况下,但在许多情况下。我知道很多人说这是“Pythonic”方式,但这是我与他们分道扬镳的一个领域。对我来说,它既不是很高效也不是很优雅,所以,我倾向于只将它用于错误捕获和报告。

我会抱怨 PHP、perl、ruby、C 甚至是该死的 shell 都有简单的函数来测试整数引擎的字符串,但是在验证这些假设时的尽职调查让我大吃一惊!显然,这种缺乏是一种常见的疾病。

这是布鲁诺帖子的快速而肮脏的编辑:

import sys, time, re

g_intRegex = re.compile(r"^([+-]?[1-9]\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
    'abc 123',
    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"^([+-]?[1-9]\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 check_int(s):
    s = str(s)
    if s[0] in ('-', '+'):
        return s[1:].isdigit()
    return s.isdigit()    


def timeFunc(func, times):
    t1 = time.time()
    for n in range(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:
        if type(v) == type(''):
            sys.stdout.write("'%s'" % v)
        else:
            sys.stdout.write("%s" % str(v))
        for func in funcs:
            sys.stdout.write( "\t\t%s\t|" % func(v))
        sys.stdout.write("\r\n") 

if __name__ == '__main__':
    print()
    print("tests..")
    testFuncs((isInt_try, isInt_str, isInt_re, isInt_re2, check_int))
    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))
    print("check_int:   %6.4f" % timeFunc(check_int, 10000))

以下是性能比较结果:

timings..
isInt_try:   0.6426
isInt_str:   0.7382
isInt_re:    1.1156
isInt_re2:   0.5344
check_int:   0.3452

AC方法可以扫描一次,然后完成。我认为,扫描字符串一次的 AC 方法是正确的做法。

编辑:

我已经更新了上面的代码以在 Python 3.5 中工作,并包含当前投票最多的答案中的 check_int 函数,并使用我能找到的当前最流行的正则表达式来测试整数罩。这个正则表达式拒绝像“abc 123”这样的字符串。我添加了“abc 123”作为测试值。

非常有趣的是,在这一点上,所有测试的函数都没有返回正确的答案,包括 try 方法、流行的 check_int 函数和用于测试整数罩的最流行的正则表达式。测试值(嗯,取决于您认为正确答案是什么;请参阅下面的测试结果)。

内置的 int() 函数静默截断浮点数的小数部分并返回小数点前的整数部分,除非先将浮点数转换为字符串。

check_int() 函数对像 0.0 和 1.0(从技术上讲是整数)这样的值返回 false,对像 '06' 这样的值返回 true。

以下是当前(Python 3.5)测试结果:

              isInt_try |       isInt_str       |       isInt_re        |       isInt_re2       |   check_int   |
0               True    |               True    |               True    |               True    |       True    |
1               True    |               True    |               True    |               True    |       True    |
-1              True    |               True    |               True    |               True    |       True    |
1.0             True    |               True    |               False   |               False   |       False   |
-1.0            True    |               True    |               False   |               False   |       False   |
'0'             True    |               True    |               True    |               True    |       True    |
'0.'            False   |               True    |               False   |               False   |       False   |
'0.0'           False   |               True    |               False   |               False   |       False   |
'1'             True    |               True    |               True    |               True    |       True    |
'-1'            True    |               True    |               True    |               True    |       True    |
'+1'            True    |               True    |               True    |               True    |       True    |
'1.0'           False   |               True    |               False   |               False   |       False   |
'-1.0'          False   |               True    |               False   |               False   |       False   |
'+1.0'          False   |               True    |               False   |               False   |       False   |
'06'            True    |               True    |               False   |               False   |       True    |
'abc 123'       False   |               False   |               False   |               False   |       False   |
1.1             True    |               False   |               False   |               False   |       False   |
-1.1            True    |               False   |               False   |               False   |       False   |
'1.1'           False   |               False   |               False   |               False   |       False   |
'-1.1'          False   |               False   |               False   |               False   |       False   |
'+1.1'          False   |               False   |               False   |               False   |       False   |
'1.1.1'         False   |               False   |               False   |               False   |       False   |
'1.1.0'         False   |               False   |               False   |               False   |       False   |
'1.0.1'         False   |               False   |               False   |               False   |       False   |
'1.0.0'         False   |               False   |               False   |               False   |       False   |
'1.0.'          False   |               False   |               False   |               False   |       False   |
'1..0'          False   |               False   |               False   |               False   |       False   |
'1..'           False   |               False   |               False   |               False   |       False   |
'0.0.'          False   |               False   |               False   |               False   |       False   |
'0..0'          False   |               False   |               False   |               False   |       False   |
'0..'           False   |               False   |               False   |               False   |       False   |
'one'           False   |               False   |               False   |               False   |       False   |
<obj..>         False   |               False   |               False   |               False   |       False   |
(1, 2, 3)       False   |               False   |               False   |               False   |       False   |
[1, 2, 3]       False   |               False   |               False   |               False   |       False   |
{'one': 'two'}  False   |               False   |               False   |               False   |       False   |
' 0 '           True    |               True    |               True    |               True    |       False   |
' 0.'           False   |               True    |               False   |               False   |       False   |
' .0'           False   |               False   |               False   |               False   |       False   |
'.01 '          False   |               False   |               False   |               False   |       False   |

刚才我尝试添加此功能:

def isInt_float(s):
    try:
        return float(str(s)).is_integer()
    except:
        return False

它的性能几乎与 check_int (0.3486) 一样好,并且对于 1.0 和 0.0 以及 +1.0 和 0. 和 .0 等值返回 true。但它也为'06'返回true,所以。我猜,选择你的毒药。


也许部分原因在于整数本身有点随意。编程系统不能奢侈地假设它总是十进制表示。 0x4df,在某些地方是一个有效的整数,而 0891 在其他地方不是。我害怕想到在这些检查中使用 unicode 会发生什么。
+1 时间。我同意对于这样一个简单的问题,整个异常业务并不是很优雅。对于这样一个常见的问题,你会期望一个内置的辅助方法......
我知道这个线程基本上处于休眠状态,但考虑到运行时 +1。行长并不总是表明潜在的复杂性;当然,try/except 可能看起来很简单(并且易于阅读,这也很重要),但这是一项昂贵的操作。我认为偏好层次结构应该总是如下所示: 1. 一个易于阅读的显式解决方案(SilentGhost's)。 2. 一个易于阅读的隐式解决方案(Triptych's)。 3.没有三个。
感谢您对这样一个看似微不足道的话题进行了详尽的调查。我将使用 isInt_str(),不管是否是 pythonic。困扰我的是我没有找到任何关于 v.find('..') 含义的信息。这是某种特殊的查找语法还是数字字符串的边缘情况?
是的,有点过时但仍然非常好和相关的分析。在 Python 3.5 中,try 更高效:isInt_try: 0.6552 / isInt_str: 0.6396 / isInt_re: 1.0296 / isInt_re2: 0.5168。
C
Catbuilts

str.isdigit() 应该可以解决问题。

例子:

str.isdigit("23") ## True
str.isdigit("abc") ## False
str.isdigit("23.4") ## False

编辑:正如@BuzzMoschetti 指出的那样,这种方式会因负数而失败(例如,“-23”)。如果您的 input_num 可能小于 0,请在应用 str.isdigit() 之前使用 re.sub(regex_search,regex_replace,contents)。例如:

import re
input_num = "-23"
input_num = re.sub("^-", "", input_num) ## "^" indicates to remove the first "-" only
str.isdigit(input_num) ## True

因为 -23 产生错误。
@BuzzMoschetti 你是对的。一种快速的解决方法是在应用 str.isdigit() 之前通过 re.replace(regex_search,regex_replace,contents) 删除减号
我正在寻找这个!尝试从 CSV 解析正整数,这非常完美!
s.isnumeric() 有什么区别?
让我用几个例子来说明:对于字节数,例如,s = b'123',s.isdigit()=True 但 s.isnumeric() 和 s.isdecimal() 会抛出 AttributeError。对于中文或罗马数字,如 s = '三叁' 或 s = 'Ⅲ',s.isdigit()=False 和 s.isdecimal() =False,但 s.isnumeric()=True。
G
Greg Hewgill

使用正则表达式:

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() 只编译一次正则表达式。


+1:表明与 try/except 相比,这非常复杂且昂贵。
我觉得这本质上是@SilentGhost 提供的“isnumeric”解决方案的一个较慢的自定义版本。
@Greg:由于@SilentGhost 没有正确覆盖标志,所以这个版本确实有效。
@S.Lott:当然,任何能够在 SO 上发帖的人都可以将我的示例扩展到涵盖标志。
正则表达式是最复杂和最晦涩的东西,我发现上面的简单检查明显更清楚,即使我认为它仍然丑陋,这更丑陋。
B
Bruno Bronosky

正确的 RegEx 解决方案将结合 Greg Hewgill 和 Nowell 的想法,但不使用全局变量。您可以通过将属性附加到方法来完成此操作。另外,我知道将导入放在一个方法中是不受欢迎的,但我想要的是像 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 obj 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(obj) else 'NOT an integer')
        integre = ('an integre' if isIntegre(obj) else 'NOT an integre')
        # Make strings look like strings in the output
        if isinstance(obj, str):
            obj = ("'%s'" % (obj,))
        print("%30s is %14s is %14s" % (obj, integer, integre))

对于班级中不那么冒险的成员,这里是输出:

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

我同意我的测试套件是矫枉过正。我喜欢在编写代码时证明我的代码有效。但是你认为我的 isInteger 函数是不是有点矫枉过正?肯定不是。
我刚投了反对票,没有任何评论。人怎么了?我了解千禧一代现在使用“喜欢”作为“已读回执”。但是他们现在是否使用反对票作为“不是我选择的方法”标记?也许他们没有意识到它会从您自己的声誉中减去 2 分来否决答案。 SO/SE 这样做是为了鼓励仅因错误信息而投反对票,在这种情况下,我希望您能发表评论。
M
Martial P
>>> "+7".lstrip("-+").isdigit()
True
>>> "-7".lstrip("-+").isdigit()
True
>>> "7".lstrip("-+").isdigit()
True
>>> "13.4".lstrip("-+").isdigit()
False

所以你的功能是:

def is_int(val):
   return val.lstrip("-+").isdigit()

is_int("2") 引发 IndexError。
``` def is_int(val): ... return val.lstrip("-+").isdigit() ... is_int("2") True ``` 它不会导致错误。这是 imo 在不依赖昂贵或奇怪的解决方案的情况下实际满足需求的最佳答案。
不错,但例如 is_int('+++25') 返回 True
m
mRotten

我一直这样做 b/c 我对使用 try/except 模式有一种温和但不可否认的非理性厌恶。我用这个:

all([xi in '1234567890' for xi in x])

它不包含负数,因此您可以去掉左侧的所有减号,然后检查结果是否包含 0-9 的数字:

all([xi in '1234567890' for xi in x.lstrip('-')])

如果您不确定输入是字符串,也可以将 x 传递给 str():

all([xi in '1234567890' for xi in str(x).lstrip('-')])

有一些(边缘?)情况会崩溃:

它不适用于各种科学和/或指数符号(例如 1.2E3、10^3 等)——两者都将返回 False。我认为其他答案也不适用,甚至 Python 3.8 也有不一致的意见,因为 type(1E2) 给出 而 type(10^2) 给出 。空字符串输入给出 True。前导加号(例如“+7”)给出 False。只要它们是前导字符,就会忽略多个减号。这种行为类似于 python 解释器*,类型(---1)返回 。但是,它与 int('---1') 给出错误的解释器并不完全一致,但我的解决方案使用相同的输入返回 True。

因此,它不适用于 每个 可能的输入,但如果您可以排除这些输入,这是一个 OK 的单行检查,如果 x 不是整数则返回 False,如果 x 是则返回 True一个整数。但是,如果您真的想要 完全 模拟内置 int() 的行为,则最好使用 try/except。

不知道是不是pythonic,但就是一行,代码的作用也比较清楚。

*我并不是说解释器忽略前导减号,只是任何数量的前导减号都不会改变结果是整数。 int(--1) 实际上被解释为 -(-1) 或 1。int(---1) 被解释为 -(-(-1)) 或 -1。所以偶数个前导减号给出一个正整数,奇数个负号给出一个负整数,但结果总是一个整数。


这将为 '12-34' 返回 True
@AMC 是的,好点,我认为这值得排除。我编辑了我的答案,其中引入了另一个我认为可以接受的警告。但是,这表明这是一个主观问题,b/c 我们必须假设哪些字符串是可接受的整数表示,哪些不是可接受的整数表示。我们也不知道我们可以对输入做出什么假设。 .replace().lstrip() 实现都足以满足 OP 的示例。
N
Nowell

Greg Hewgill 的方法缺少一些组件:前导“^”只匹配字符串的开头,并预先编译 re。但是这种方法可以让你避免尝试:exept:

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

我很想知道你为什么要避免尝试:除了?


风格问题。我认为“try/except”应该只用于实际错误,而不是正常的程序流程。
@Udi Pasmon:Python 大量使用 try/except “正常”程序流。例如,每个迭代器都会因引发异常而停止。
-1 :尽管您编译正则表达式的提示是正确的,但您在另一方面批评 Greg 是错误的: re.match 匹配字符串的开头,因此模式中的 ^ 实际上是多余的。 (当您使用 re.search 时,情况会有所不同)。
S.Lott - 这在 python 中被认为是合理的流程吗?这与其他语言有何不同?也许值得一个单独的问题。
Python 对 try/except 的大量使用已在 SO 上介绍。尝试搜索'[python] except'
G
Grey2k

我使用的最简单的方法

def is_int(item: str) -> bool:
    return item.lstrip('-+').isdigit()

我不敢相信没有内置的 .isint() 函数以及 .isfloat() 和 .isbool() 有什么理由吗?
是的,这有点可笑
-+123 为真
V
Vladyslav Savchenko

我认为

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

最好重写为:

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

因为 s[1:] 也创建了一个新字符串

但更好的解决方案是

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

猜猜 replace 做了什么?此外,例如,这将错误地接受 5-2
如果 s='-' 将抛出 IndexError
s = '-'; s.replace('-', '').isdigit() -> False
s.lstrip('+-').isdigit() 接受 -+1+++++++1 之类的内容
请注意,产生字符串也是坏习惯。这是一个比 try catch 更少的问题,但也很丑陋。
S
SuperNova

可以使用下面的方法来检查。

def check_if_string_is_int(string1):
    for character in string1:
        if not character.isdigit():
            return "Not a number"
    else:
        return "Is a number"

b
brw59

我真的很喜欢 Shavais 的帖子,但我又添加了一个测试用例(以及内置的 isdigit() 函数):

def isInt_loop(v):
    v = str(v).strip()
    # swapping '0123456789' for '9876543210' makes nominal difference (might have because '1' is toward the beginning of the string)
    numbers = '0123456789'
    for i in v:
        if i not in numbers:
            return False
    return True

def isInt_Digit(v):
    v = str(v).strip()
    return v.isdigit()

并且它显着地持续超过其他时间:

timings..
isInt_try:   0.4628
isInt_str:   0.3556
isInt_re:    0.4889
isInt_re2:   0.2726
isInt_loop:   0.1842
isInt_Digit:   0.1577

使用普通的 2.7 python:

$ python --version
Python 2.7.10

我添加的两个测试用例(isInt_loop 和 isInt_digit)都通过了完全相同的测试用例(它们都只接受无符号整数),但我认为人们可以更聪明地修改与内置 isdigit 相对的字符串实现(isInt_loop) () 函数,所以我将它包括在内,即使执行时间略有不同。 (这两种方法都比其他方法好很多,但不要处理额外的东西: "./+/-" )

此外,我确实发现有趣的是,正则表达式(isInt_re2 方法)在 Shavais 在 2012 年(目前是 2018 年)执行的同一测试中击败了字符串比较。也许正则表达式库已经改进?


r
rmtheis

在我看来,这可能是最直接和最pythonic的方法。我没有看到这个解决方案,它与正则表达式基本相同,但没有正则表达式。

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

set(input_string) == set(string.digits) 如果我们在开头跳过 '-+ ' 并在结尾跳过 .0E-1
R
Reut Sharabani

这是一个解析而不会引发错误的函数。它处理失败时返回 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)

一些测试:

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

k
krubo

如果您只想接受较低的 ascii 数字,请执行以下测试:

Python 3.7+:(u.isdecimal() and u.isascii())

Python <= 3.6:(u.isdecimal() and u == str(int(u)))

其他答案建议使用 .isdigit().isdecimal(),但这些 both include some upper-unicode characters 例如 '٢' (u'\u0662'):

u = u'\u0662'     # '٢'
u.isdigit()       # True
u.isdecimal()     # True
u.isascii()       # False (Python 3.7+ only)
u == str(int(u))  # False

这不会处理负值或空白填充值,int() 可以很好地处理这两个值。
K
Konstantin Smolyanin

前提条件:

我们谈论的是整数(不是小数/浮点数);

内置 int() 的行为对我们来说是一个标准(有时很奇怪:“-00”是它的正确输入)

简短的回答:

使用以下代码。它是简单正确(虽然此线程中的许多变体不是)并且几乎两次优于 try/exceptregex 变体.

def is_int_str(string):
    return (
        string.startswith(('-', '+')) and string[1:].isdigit()
    ) or string.isdigit()

TL;DR 答案:

我测试了 3 个主要变体 (1) try/except,(2) re.match() 和 (3) 字符串操作(见上文)。第三种变体比 try/exceptre.match() 快大约两倍。顺便说一句:正则表达式变体是最慢的!请参阅下面的测试脚本。

import re
import time


def test(func, test_suite):
    for test_case in test_suite:
        actual_result = func(*test_case[0])
        expected_result = test_case[1]
        assert (
            actual_result == expected_result
        ), f'Expected: {expected_result} but actual: {actual_result}'


def perf(func, test_suite):
    start = time.time()

    for _ in range(0, 1_000_000):
        test(func, test_suite)

    return time.time() - start


def is_int_str_1(string):
    try:
        int(string)
        return True
    except ValueError:
        return False


def is_int_str_2(string):
    return re.match(r'^[\-+]?\d+$', string) is not None


def is_int_str_3(string):
    return (
        string.startswith(('-', '+')) and string[1:].isdigit()
    ) or string.isdigit()


# Behavior of built-in int() function is a standard for the following tests
test_suite = [
    [['1'], True],  # func('1') -> True
    [['-1'], True],
    [['+1'], True],
    [['--1'], False],
    [['++1'], False],
    [['001'], True],  # because int() can read it
    [['-00'], True],  # because of quite strange behavior of int()
    [['-'], False],
    [['abracadabra'], False],
    [['57938759283475928347592347598357098458405834957984755200000000'], True],
]

time_span_1 = perf(is_int_str_1, test_suite)
time_span_2 = perf(is_int_str_2, test_suite)
time_span_3 = perf(is_int_str_3, test_suite)

print(f'{is_int_str_1.__name__}: {time_span_1} seconds')
print(f'{is_int_str_2.__name__}: {time_span_2} seconds')
print(f'{is_int_str_3.__name__}: {time_span_3} seconds')

输出是:

is_int_str_1: 4.314162969589233 seconds
is_int_str_2: 5.7216269969940186 seconds
is_int_str_3: 2.5828163623809814 seconds

我认为您的正则表达式变体是最慢的,因为您没有先预编译正则表达式模式。当我预编译正则表达式时,它成为第二快。在 Python 3.7 上:9.66 | 7.03 | 4.86,在 Python 3.8 上:7.78 | 5.56 | 4.57
a
agomcas

我有一种根本不使用 int 的可能性,除非字符串不代表数字,否则不应引发异常

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

它应该适用于浮点接受的任何类型的字符串,正数,负数,工程符号......


J
Jesko Hüttenhain

我建议如下:

import ast

def is_int(s):
    return isinstance(ast.literal_eval(s), int)

docs

安全地评估包含 Python 文字或容器显示的表达式节点或字符串。提供的字符串或节点只能由以下 Python 文字结构组成:字符串、字节、数字、元组、列表、字典、集合、布尔值和无。

我应该注意,当针对不构成 Python 文字的任何内容调用时,这将引发 ValueError 异常。由于问题要求没有尝试/例外的解决方案,因此我有一个 Kobayashi-Maru 类型的解决方案:

from ast import literal_eval
from contextlib import suppress

def is_int(s):
    with suppress(ValueError):
        return isinstance(literal_eval(s), int)
    return False

¯\_(ツ)_/¯


将您的“Kobayashi-Maru”代码与 python 3.8 一起使用,我仍然会遇到像 '123abc' - SyntaxError: unexpected EOF while parsing 这样的输入异常
H
Hmerman6006

检查后将值转换为字符串是整数,然后检查字符串的第一个字符值是 -+ 以及字符串的其余部分 isdigit。最后只需检查 isdigit

test = ['1', '12015', '1..2', 'a2kk78', '1.5', 2, 1.24, '-8.5', '+88751.71', '-1', '+7']

查看

for k,v in enumerate(test): 
    print(k, v, 'test: ', True if isinstance(v, int) is not False else True if str(v)[0] in ['-', '+'] and str(v)[1:].isdigit() else str(v).isdigit())

结果

0 1 test:  True
1 12015 test:  True
2 1..2 test:  False
3 a2kk78 test:  False
4 1.5 test:  False
5 2 test:  True
6 1.24 test:  False
7 -8.5 test:  False
8 +88751.71 test:  False
9 -1 test:  True
10 +7 test:  True

C
Carlos Vega

我想这个问题与速度有关,因为 try/except 有时间损失:

测试数据

首先,我创建了一个包含 200 个字符串、100 个失败字符串和 100 个数字字符串的列表。

from random import shuffle
numbers = [u'+1'] * 100
nonumbers = [u'1abc'] * 100
testlist = numbers + nonumbers
shuffle(testlist)
testlist = np.array(testlist)

numpy 解决方案(仅适用于数组和 unicode)

np.core.defchararray.isnumeric 也可以使用 unicode 字符串 np.core.defchararray.isnumeric(u'+12') 但它返回和数组。因此,如果您必须进行数千次转换并且缺少数据或非数字数据,这是一个很好的解决方案。

import numpy as np
%timeit np.core.defchararray.isnumeric(testlist)
10000 loops, best of 3: 27.9 µs per loop # 200 numbers per loop

尝试/除

def check_num(s):
  try:
    int(s)
    return True
  except:
    return False

def check_list(l):
  return [check_num(e) for e in l]

%timeit check_list(testlist)
1000 loops, best of 3: 217 µs per loop # 200 numbers per loop

似乎 numpy 解决方案要快得多。


H
HaulCozen

呃..试试这个:

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

如果您不输入不是数字的字符串,则此方法有效。

而且(我忘了放数字检查部分。),有一个函数检查字符串是否是数字。它是 str.isdigit()。这是一个例子:

a = 2
a.isdigit()

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


我认为您需要在分配给 a 的值 2 周围加上引号。
-1 问题:“检查一个字符串是否代表一个 int,而不使用 Try/Except?”对于@Caroline Alexiou
@蚱蜢int_check("ardvark")