【问题标题】:Validating integers in Python strings验证 Python 字符串中的整数
【发布时间】:2026-02-18 05:30:01
【问题描述】:

我们有大量的字符串,其中包含可能是整数的子字符串,例如。

mystring = "123 345 456 567 678 789"

并且需要验证:

一个。每个子字符串实际上是一个整数,例如。 mystring = "123 345 456 567 abc 789" 在到达 'abc' 时失败

b.每个整数都在 0 mystring = "123 -345 456 567 678 789" 在达到 '-345' 时失败

一种解决方案是:

mylist= [int(i) for i in mystring.split() if isinstance(int(i), int) and (0 <= int(i) <= 10000)]

问题是:

我。在列表推导中,对于每个 i,int(i) 是被评估一次还是多次?

二。有没有更快的替代方法(因为字符串的体积很大,每个字符串可能包含数百到数千个整数)?

【问题讨论】:

  • 一个。每个整数都是一个整数 ??
  • 将列表分配给名为mystring 的变量听起来是个相当糟糕的主意?
  • 一个。他显然是指子字符串。 mystring 绝对应该是该作业左侧的 mylist
  • @jgritty 将上次分配更改为 mylist。

标签: python string validation integer


【解决方案1】:

我想我可能会使用类似的东西:

try:
    if not all( (0 <= int(i) <= 10000) for i in mystring.split() ):
       raise ValueError("arg!")
except ValueError:
    print "Oops, didn't pass"

这样做的好处是,如果某些内容无法转换为 int 或不在正确范围内,它会短路。

这是一个愚蠢的测试:

def test_str(mystring):
    try:
        return all( (0 <= int(i) <= 10000) for i in mystring.split() )
    except ValueError:
        return False

print test_str("123 345 456 567 abc 789")
print test_str("123 345 456 567 -300 789")
print test_str("123 345 456 567 300 789")

【讨论】:

  • 啊,这很棒,因为它在失败时会短路,并且不使用 for 循环。不知道“全部”运算符 - 也有助于其他验证。最好的。
【解决方案2】:

int(i) 被多次评估。此外,isinstance(int(i), int) 没有用处,因为int() 会在非整数输入上引发异常,而不是静默返回非整数。

将代码编写为老式循环并没有错。它在错误处理方面为您提供了最大的灵活性。如果您担心效率,请记住,列表解析只不过是此类循环的语法糖。

intlist = []
for part in mystring.split():
    try:
        val = int(part)
    except ValueError:
        continue  # or report the error
    if val < 0 or val > 10000:
        continue  # or report the error
    intlist.append(val)

【讨论】:

    【解决方案3】:

    如果存在非数字字符串,您的解决方案将不起作用:

    ValueError: int() 以 10 为底的无效文字:'abc'

    我会这样做:

    mystring = "123 345 456 -123 567 abc 678 789"
    
    mylist = []
    for i in mystring.split():
        try:
            ii = int(i)
        except ValueError:
            print "{} is bad".format(i)
        if 0 <= ii <= 10000:
            mylist.append(ii)
        else:
            print  "{} is out of range".format(i)
    print mylist
    

    回答您的问题:

    我。是的,不止一次。

    二。是的,已经提供了几个示例。

    我的输出如下所示:

    -123 超出范围

    abc 不好

    [123、345、456、567、567、678、789]

    【讨论】:

      【解决方案4】:

      你也可以使用正则表达式:

      import re
      mystring = "123 345 456 567 abc 789 -300 ndas"
      
      re_integer = r'(-??\d+)'
      re_space_or_eof = r'(\ |$)' #using space or eof so we don't match floats
      
      #match all integers
      matches = re.finditer(re_integer + re_space_or_eof, mystring)
      
      #extract the str, convert to int for all matches
      int_matches = [int(num.groups()[0]) for num in matches]
      
      #filter based on criteria
      in_range = [rnum for rnum in int_matches if 0 <= rnum <=10000]
      
      >>> in_range
      [123, 345, 456, 567, 789]
      

      【讨论】:

        【解决方案5】:

        似乎我错过了激烈的辩论,但这里有另一种可能更快的方法:

        >>> f = lambda(s): set(s) <= set('0123456789 ') and not filter(lambda n: int(n) > 10000, s.split())
        

        测试:

        >>> s1 = '123 345 456 567 678 789'
        >>> s2 = '123 345 456 567 678 789 100001'
        >>> s3 = '123 345 456 567 678 789 -3'
        >>> s4 = '123 345 456 567 678 789 ba'
        >>> f(s1)
        True
        >>> f(s2)
        False
        >>> f(s3)
        False
        >>> f(s4)
        False
        

        我没有计时,但我怀疑它可能比其他提议的解决方案更快,因为集合比较已经处理了 x &lt; 0 测试和不可解析的字符串,如 abc。由于两个测试(集合比较和数值范围)在逻辑上是连接的,第一个失败将阻止运行第二个。

        HTH!

        【讨论】: