[英]Validating integers in Python strings
我们有很多字符串,其中包含可能是整数的子字符串。
mystring = "123 345 456 567 678 789"
并需要验证:
一种。 每个子串实际上是一个整数,例如。 in mystring = "123 345 456 567 abc 789"
到达'abc'时失败
b。 每个整数都在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。 是否有另一种方法可以更快(因为字符串的数量很大,每个字符串可以包含数百到数千个整数)?
我认为我可能会使用类似:
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")
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)
如果存在非数字字符串,则您的解决方案将不起作用:
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]
您也可以使用正则表达式:
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]
似乎我错过了辩论的激烈程度,但这是另一种可能更快的方法:
>>> 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
这样的不可解析字符串。 由于两个测试(集合比较和数值范围)在逻辑上结合在一起,因此第一个测试的失败将阻止第二个测试的运行。
HTH!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.