簡體   English   中英

驗證Python字符串中的整數

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM