1

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

mystring = "123 345 456 567 678 789"

并且需要验证:

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

湾。每个整数都在 0 <= i <= 10000 的范围内,例如。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) 是被评估一次还是多次?

ii. 是否有更快的替代方法(因为字符串的数量很大,每个字符串可能包含数百到数千个整数)?

4

5 回答 5

5

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

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

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

这是一个愚蠢的测试:

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")
于 2013-01-23T20:00:57.437 回答
1

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)
于 2013-01-23T20:03:11.513 回答
0

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

>>> 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 < 0测试和不可解析的字符串,例如abc. 由于两个测试(集合比较和数值范围)在逻辑上是连接的,第一个测试失败将阻止运行第二个测试。

于 2013-01-24T08:26:29.133 回答
0

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

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

要回答您的问题:

一世。是的,不止一次。

ii. 是的,已经提供了几个例子。

我的输出如下所示:

-123 超出范围

abc不好

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

于 2013-01-23T20:08:54.653 回答
0

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

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]
于 2013-01-23T20:38:27.477 回答