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

Ada*_*tan 413 python string integer

有没有办法判断一个字符串是否代表一个整数(例如'3','-17'但不是'3.14''asfasfas')没有使用try/except机制?

is_int('3.14') = False
is_int('-7')   = True
Run Code Online (Sandbox Code Playgroud)

Sil*_*ost 671

您可以使用正整数.isdigit:

>>> '16'.isdigit()
True
Run Code Online (Sandbox Code Playgroud)

但它不适用于负整数.假设你可以尝试以下方法:

>>> s = '-17'
>>> s.startswith('-') and s[1:].isdigit()
True
Run Code Online (Sandbox Code Playgroud)

它不适用于'16.0'格式,这与int此类意义上的类似.

编辑:

def check_int(s):
    if s[0] in ('-', '+'):
        return s[1:].isdigit()
    return s.isdigit()
Run Code Online (Sandbox Code Playgroud)

  • 注意:`u'²'.isdigit()`是真的但是`int(u'²')`引发了ValueError.请改用"u.isdecimal()".`str.isdigit()`是依赖于语言环境的Python 2. (21认同)
  • 没有额外的特殊情况,这不会处理"+17". (5认同)
  • @Roberto:当然应该!而且我相信你有能力这样做! (4认同)
  • 这似乎很重要,也很复杂,足以保证内置真正.... (4认同)
  • `check_int('')`会引发一个异常而不是返回`False` (3认同)

Tri*_*ych 355

如果你真的只是厌倦try/except了在各处使用s,请写一个帮助函数:

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

>>> print RepresentsInt("+123")
True
>>> print RepresentsInt("10.0")
False
Run Code Online (Sandbox Code Playgroud)

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

  • 那么解决复杂机制的简单问题是pythonic吗?有一个算法用于检测int的内部函数"int" - 我不明白为什么不将它暴露为布尔函数. (108认同)
  • @Aivar:这5行函数不是一个复杂的机制. (74认同)
  • 我不知道为什么这是接受的答案或有这么多的赞成,因为这与OP的要求正好相反. (39认同)
  • 除了:`>>> print RepresentsInt(10.0)``True`` >>> print RepresentsInt(10.06)``True` (30认同)
  • 我想这是"pythonic",因为如果Python认为字符串是int,那么你的程序也是如此.如果Python发生了变化,程序也会发生变化,而且不会改变单行代码.这有一些价值.根据具体情况,这可能是正确的做法. (5认同)
  • @Dannid:问题是输入**字符串**.在你的情况下你可以使用`.is_integer()`方法. (4认同)
  • 问题包括:"*不使用try/except机制?*".由于使用了`try/except`(即使包含在func中),也不满足该要求. (4认同)
  • @kevlarr 如果存在性能问题,问题应该是“将字符串转换为 int 的最快方法是什么”*。询问如何在没有“尝试”的情况下做到这一点只是在询问错误的代码。 (3认同)
  • 这真的让我很困扰,这是“Pythonic”的方式。这是一种糟糕的语言设计软件工程,当然并不比仅仅拥有一个可以调用的 is_int 函数更简单。通过将其称为“Pythonic”,它本质上是社区表达“这是一个功能,而不是一个错误!”的方式。 (3认同)
  • OP 特别要求一个没有 try/ except 的解决方案。 (3认同)
  • 在必须以高频率执行的代码中使用此代码之前,您应该看到Shavais的帖子位于此页面上解决方案的时间点.最快的解决方案是我的纯字符串方法链接. (2认同)
  • @Aivar:**没有**的其他答案都是正确的.没有!!!它们要么不接受`int()`接受的所有值,要么它们无法达到它们自己的整数定义(例如,接受一个浮点数也是整数的字符串(`float(s).is_integer( )"是真的)). (2认同)
  • 事实:此方法不适用于带下划线的字符串:`>>> int("2019_01_01")` 返回 `20190101` (2认同)
  • 对此添加另一个角度:从分隔文本文件源读取数据时,测试字符串是否能够转换为整数是一项常见任务。对于多行数据,同时存在整数和非整数可能是常见的,这将不利于使用异常来处理(由于性能问题,尤其是在许多字段和数十亿行中)。由于这个答案没有解决OP的明确要求(这不是FUD),然后受到了强烈的辩护,它破坏了例外实际上是不合适的合法情况。 (2认同)
  • @KonstantinSmolyanin 每个其他解决方案的问题在于,要么它只对字符串/字符的子集(例如 ASCII)正确,要么不能保证任何未来版本的 Python 的正确性(据我所知)。该解决方案对于任何可能的字符串都是正确的,并且只要语言没有任何重大更改,就保证保持正确。当然,在很多用例中,您已经局限于字符串的子集,在这种情况下,其他一些解决方案可能非常好(甚至比这个解决方案更好)。 (2认同)

Sha*_*ais 88

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

我会抱怨PHP,perl,ruby,C,甚至是怪异的shell都有简单的函数来测试整数引擎的字符串,但是在验证这些假设的尽职调查让我感到沮丧!显然这种缺乏是一种常见的疾病.

这是Bruno的帖子快速而又脏的编辑:

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))
Run Code Online (Sandbox Code Playgroud)

以下是性能比较结果:

timings..
isInt_try:   0.6426
isInt_str:   0.7382
isInt_re:    1.1156
isInt_re2:   0.5344
check_int:   0.3452
Run Code Online (Sandbox Code Playgroud)

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

编辑:

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

对我来说非常有趣的是,在这一点上,测试的任何功能,包括try方法,流行的check_int函数,以及用于测试整数引擎的最流行的正则表达式,都会返回所有的正确答案.测试值(嗯,取决于您认为正确的答案;请参阅下面的测试结果).

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

对于像0.0和1.0这样的值(技术上是整数),check_int()函数返回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   |
Run Code Online (Sandbox Code Playgroud)

刚才我尝试添加这个功能:

def isInt_float(s):
    try:
        return float(str(s)).is_integer()
    except:
        return False
Run Code Online (Sandbox Code Playgroud)

它的执行效果几乎和check_int(0.3486)一样,并且对于1.0和0.0以及+1.0和0以及.0之类的值返回true,依此类推.但它也会在'06'中返回true,所以.我想,选择你的毒药.

  • 我知道这个线程基本上是休眠的,但是考虑到运行时的+1.线长并不总是表明潜在的复杂性; 并且肯定,try/except可能看起来很简单(并且阅读简单,这也很重要),但它*是一项代价高昂的操作.我认为偏好层次结构应该总是如下所示:1.易于阅读的显式解决方案(SilentGhost).2.易于阅读的隐式解决方案(Triptych's).没有三个. (9认同)
  • 是的,有点过时,但仍然非常好,相关的分析.在Python 3.5中,try`更有效:isInt_try:0.6552/isInt_str:0.6396/isInt_re:1.0296/isInt_re2:0.5168. (3认同)
  • +1为时间.我同意,对于这样一个简单的问题,这整个异常业务并不是很优雅.你期望为这样一个常见问题构建帮助方法...... (2认同)

Gre*_*ill 25

使用正则表达式:

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

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

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

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

  • +1:显示与try/except相比,这是非常复杂和昂贵的. (19认同)
  • 我觉得这本质上是@SilentGhost提供的'isnumeric'解决方案的一个较慢的自定义版本. (2认同)
  • 正则表达式是关于存在的最复杂和最模糊的东西,我发现上面的简单检查要清楚得多,即使我认为它仍然很难看,这是更加丑陋的. (2认同)

Cat*_*lts 23

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 产生错误。 (2认同)
  • @BuzzMoschetti 你是对的。一种快速修复方法是在应用 str.isdigit() 之前通过 re.replace(regex_search,regex_replace,contents) 删除减号 (2认同)

Bru*_*sky 17

适当的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))
Run Code Online (Sandbox Code Playgroud)

对于不太冒险的班级成员,这是输出:

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
Run Code Online (Sandbox Code Playgroud)

  • 我同意我的测试套件有点矫枉过正.我喜欢**证明**我写代码时我的代码有效.但是你认为我的isInteger函数是否过度杀伤?当然不是. (3认同)
  • 我刚投了反对票,没有评论。人怎么了?我知道千禧一代现在使用“喜欢”作为“阅读回执”。但是他们现在是否使用反对票作为“不是我选择的方法”的标记?也许他们没有意识到它会从 **你自己的声誉** 中减去 2 分来否决一个答案。SO/SE 这样做是为了鼓励仅因错误信息而拒绝投票,在这种情况下,我希望您 ** 发表评论**。 (2认同)

alk*_*333 14

>>> "+7".lstrip("-+").isdigit()
True
>>> "-7".lstrip("-+").isdigit()
True
>>> "7".lstrip("-+").isdigit()
True
>>> "13.4".lstrip("-+").isdigit()
False
Run Code Online (Sandbox Code Playgroud)

所以你的功能是:

def is_int(val):
   return val.lstrip("-+").isdigit()
Run Code Online (Sandbox Code Playgroud)


mRo*_*ten 6

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

all([xi in '1234567890' for xi in x])
Run Code Online (Sandbox Code Playgroud)

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

all([xi in '1234567890' for xi in x.lstrip('-')])
Run Code Online (Sandbox Code Playgroud)

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

all([xi in '1234567890' for xi in str(x).lstrip('-')])
Run Code Online (Sandbox Code Playgroud)

在某些(边缘?)情况下,这会崩溃:

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

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

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

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


Gre*_*y2k 6

最简单的方法,我用的

def is_int(item: str) -> bool:
    return item.lstrip('-+').isdigit()
Run Code Online (Sandbox Code Playgroud)

  • 我不敢相信没有内置 .isint() 函数以及 .isfloat() 和 .isbool() 这有什么原因吗? (2认同)

Now*_*ell 5

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

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

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

  • 风格问题。我认为“try/except”应该只用于实际错误,而不是正常的程序流程。 (3认同)
  • -1 :虽然您编译正则表达式的提示是正确的,但您在其他方面批评 Greg 是错误的:re.match 匹配字符串的 **start**,因此模式中的 ^ 实际上是多余的。(这与使用 re.search 时不同)。 (3认同)
  • @Udi Pasmon:除了“正常”程序流之外,Python 大量使用了 try/except。例如,每个迭代器都会因引发异常而停止。 (2认同)

Vla*_*nko 5

我认为

s.startswith('-') and s[1:].isdigit()
Run Code Online (Sandbox Code Playgroud)

最好重写为:

s.replace('-', '').isdigit()
Run Code Online (Sandbox Code Playgroud)

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

但更好的解决方案是

s.lstrip('+-').isdigit()
Run Code Online (Sandbox Code Playgroud)

  • 猜猜“替换”是做什么的?此外,例如,这将错误地接受“5-2”。 (3认同)

Sup*_*ova 5

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

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