2016-03-06 40 views
3

第一次發佈,我潛伏了一會兒,對這裏的幫助社區感到非常興奮。Python,正則表達式匹配數字,x,xxx,xxx,但不是xx,xx,x,

因此,由鋁Sweigart

「自動無聊的東西」這樣做,需要我建立在標準的數字格式發現號的正則表達式的鍛鍊工作。三位數字,逗號,三位數字,逗號等...

所以希望匹配1,234和23,322和1,234,567和12,但不是1,23,1或1111或其他愚蠢的東西。

我有以下幾點。

import re 

testStr = '1,234,343' 
matches = [] 
numComma = re.compile(r'^(\d{1,3})*(,\d{3})*$') 

for group in numComma.findall(str(testStr)): 
    Num = group 
    print(str(Num) + '-')   #Printing here to test each loop 
    matches.append(str(Num[0])) 

#if len(matches) > 0: 
# print(''.join(matches)) 

,輸出這個....

( '1',」 343' ) -

我不知道爲什麼中間的」 234" 被跳過。我相信,正則表達式有什麼問題。只是似乎無法把我的頭圍繞在這一個。

任何幫助或解釋將不勝感激。

跟隨編輯。因此,在遵循我可以吸收的所有建議之後,我將它完美地用於多種輸入。

import re 

testStr = '1,234,343' 
numComma = re.compile(r'^(?:\d{1,3})(?:,\d{3})*$') 

Num = numComma.findall(testStr) 
print(Num) 

給我....

[ '1234343']

太好了!但!什麼時候我的字符串輸入更改爲類似

「1234343和12345」

相同的代碼返回....

[]

哎呀...大聲笑,這是有趣的, 我必須承認。

因此,練習的目的是能夠最終掃描一段文本並挑選出這種格式的所有數字。任何見解?我認爲這將增加一個額外的元組,而不是返回一個空的...

跟進編輯:

所以,一天後(一直忙於3個女兒和蜂蜜待辦事項列表),我已經終於能夠坐下來檢查我收到的所有幫助。這是我想出來的,它看起來工作得很好。包括評論爲我自己的個人理解。再次感謝Blckknght,Saleem,mhawke和BHustus。

我的最終代碼:

import re 

testStr = '12,454 So hopefully will match 1,234 and 23,322 and 1,234,567 and 12 but not 1,23,1 or ,,1111, or anything else silly.' 

numComma = re.compile(r''' 
    (?:(?<=^)|(?<=\s)) # Looks behind the Match for start of line and whitespace 
    ((?:\d{1,3})  # Matches on groups of 1-3 numbers. 
    (?:,\d{3})*)  # Matches on groups of 3 numbers preceded by a comma 
    (?=\s|$)''', re.VERBOSE) # Looks ahead of match for end of line and whitespace 

Num = numComma.findall(testStr) 
print(Num) 

將返回:

['12,454' , '1,234','23,322' , '1,234,567', '12']

再次感謝!我在這裏有這樣一個積極的第一次發佈經驗,令人驚歎。=)

+0

你爲什麼使用findall? – Alex

+0

這不是問題,但你的正則表達式是錯誤的。第一個'*'是一個錯誤,它允許模式匹配非標準格式的東西:例如''1234''和'',123''。 –

+0

我使用的是findall,因爲我是一個完全徹底的新手,摸索着他的方式:)我會閱讀不同的方法,並遵循這裏流動的建議。 –

回答

1

問題是:

正則表達式匹配將返回每個組的元組項。 但是,區分捕獲很重要。由於您只有兩個以括號分隔的組,因此匹配將始終爲二元組:第一組和第二組。但第二組匹配兩次。

1:第一組,捕獲
,234 :第二組,捕獲
,343秒組,這意味着它覆蓋,234

不幸的是,似乎香草Python沒有一種方法來訪問比上一個類似.NET的正則表達式實施方式與其他任何一個組捕獲。 但是,如果你只是想獲得具體的數字,你最好的選擇是使用re.search(number)。如果它返回一個非None值,那麼輸入字符串是一個有效的數字。否則,它不是。

此外:A test在您的正則表達式。請注意,正如Paul Hankin所說,測試用例6和7雖然不應該匹配,但由於第一個捕獲組的第一個*會使初始組匹配任意次數,所以測試用例6和7也是如此。否則,你的正則表達式是正確的。 Fixed version.

迴應編輯:
原因,現在您正則表達式在您的正則在返回一個空集「和」是因爲^和$錨。正則表達式開頭的^ anchor表示'這個點需要在一個字符串的開頭'。 $是它的對手,說'這需要在字符串的末尾'。如果你希望你的整個字符串從頭到尾匹配模式,這很好,但如果你想挑選多個數字,你應該去掉它們。

然而!
如果您將正則表達式保留爲其當前形式的無錨點,則它現在將單獨的數字與1,23,45的各個元素進行匹配。因此,爲此,我們需要添加一個零寬度正向超前斷言,並說:'確保在這個數字之後是空格或行尾「。您可以看到更改here。尾端(?=\s|$)是我們的前瞻斷言:它不捕獲任何東西,但只是確定標準或滿足,在這種情況下,空格(\s)或(|)行結束($)。

但是:在類似的情況下,以前的正則表達式會在「1234,567」中匹配2個向前,給我們數字「234,567」,這會很糟糕。所以我們使用後面的斷言,類似於我們在末尾的前瞻:(?<!^|\s),只有在字符串開頭或數字前有空格時才匹配。該版本可以找到here,並且應該完全滿足任何非十進制數字相關的需求。

+0

你的解釋太棒了。我想我實際上可以把所有這些都包括在內。謝謝。 –

+0

很高興聽到它。不要忘記接受答案,這樣它會泡到頂端,其他人可以閱讀。 – BHustus

4

該問題是由於您在模式中使用了重複捕獲組(,\d{3})*。 Python的正則表達式引擎將匹配您的號碼的數千個和一組,但只有最後一次重複纔會被捕獲。我想你想要使用非捕獲組。添加?:每個組括號開始(我也建議,在一般原則,使用原始的字符串,雖然你不必在當前的模式逃避問題):

numComma = re.compile(r'^(?:\d{1,3})(?:,\d{3})*$') 

由於沒有組被捕獲,re.findall將返回整個匹配的文本,我認爲這是你想要的。您還可以使用re.findre.search並在返回的match對象上調用group()方法來獲取整個匹配的文本。

+1

這是一個很好的解釋,但建議的正則表達式匹配數字字符串「1234」,「123」,「1234,123」和許多其他變體 – mhawke

+0

@mhawke:是的,只是注意到了這一點。第一組的'*'也是錯誤的,雖然這不是導致問題所涉及的具體問題的原因,所以我沒有注意到它。我已經在我的答案中解決了這個模式。 – Blckknght

+0

修正後的正則表達式現在可以很好地工作。一個非常小而迂腐的觀點是,它不會接受負數......通過在開始處插入光標後加上「 - ?」可以很容易地解決這個問題。 – mhawke

0

嘗試:

import re 
p = re.compile(ur'(?:(?<=^)|(?<=\s))((?:\d{1,3})(?:,\d{3})*)(?=\s|$)', re.DOTALL) 

test_str = """1,234 and 23,322 and 1,234,567 1,234,567,891 200 and 12 but 
not 1,23,1 or ,,1111, or anything else silly""" 

for m in re.findall(p, test_str): 
    print m 

,它的輸出將是

  • 1,234
  • 23,322
  • 1,234,567
  • 1,234,567,891

你可以看到演示here

0

此正則表達式,將匹配任何有效的數量,並且將永遠不會匹配無效號碼:

(?<=^|\s)(?:(?:0|[1-9][0-9]{0,2}(?:,[0-9]{3})*))(?=\s|$)

https://regex101.com/r/dA4yB1/1

相關問題