2016-11-02 60 views
1

首先,這是作業。 (我不能在標題中使用標籤,底部的標籤列表中沒有任何內容出現在作業中,所以請讓我知道是否應該編輯其他有關此問題的內容)。Python正則表達式匹配帶重複輔音的單詞

所以我一直在閱讀python文檔和清理SO,發現幾個解決方案接近我想要的,但不是確切的。

我有我讀了一個字符串的字典:

a 
aa 
aabbaa 
... 
z 

我們在這練習的數據正則表達式的各種patters。 這裏的具體問題是返回匹配模式的單詞列表,而不是每個匹配組中的元組。

例如:

鑑於本字典一樣的一個子集:

someword 
sommmmmeword 
someworddddd 
sooooomeword 

我要回:

['sommmmmword', 'someworddddd'] 

NOT:

[('sommmmword', 'mmmmm', ...), ...] # or any other variant 

編輯:

我的推理背後的上述例子,是我想看看我可以如何避免第二次通過結果。這是不是說:

res = re.match(re.compile(r'pattern'), dictionary) 
return [r[0] for r in res] 

我特別想要一個機制,我可以只使用:

return re.match(re.compile(r'pattern'), dictionary) 

我知道這聽起來可能很傻,但我這樣做是爲了真正深入到正則表達式。我在底部提到這一點。

這是我曾嘗試:

# learned about back refs 
r'\b([b-z&&[^eiou]])\1+\b' -> # nothing 

# back refs were weird, I want to match something N times 
r'\b[b-z&&[^eiou]]{2}\b' -> # nothing 

某處在測試中,我發現一個模式返回之類的東西'\nsomeword'。我無法弄清楚它是什麼,但如果我再次找到該模式,我會在這裏包括它的完整性。

# Maybe the \b word markers don't work how I think? 
r'.*[b-z&&[^eiou]]{2}' -> # still nothing 

# Okay lets just try to match something in between anything 
r'.*[b-z&&[^eiou]].*' -> # nope 

# Since its words, maybe I should be more explicit. 
r'[a-z]*[b-z&&[^eiou]][a-z]*' -> # still nope 

# Decided to go back to grouping. 
r'([b-z&&[^eiou]])(\1)' # I realize set difference may be the issue 

# I saw someone (on SO) use set difference claiming it works 
# but I gave up on it... 

# OKAY getting close 
r'(([b-df-hj-np-tv-xz])(\2))' -> [('ll', 'l', 'l'), ...] 

# Trying the the previous ones without set difference 
r'\b(.*(?:[b-df-hj-np-tv-xz]{3}).*)\b' -> # returned everything (all words) 

# Here I realize I need a non-greedy leading pattern (.* -> .*?) 
r'\b(.*?(?:[b-df-hj-np-tv-xz]{3}).*)\b' -> # still everything 

# Maybe I need the comma in {3,} to get anything 3 or more 
r'\b(.*?(?:[b-df-hj-np-tv-xz]{3,}).*)\b' -> # still everything 

# okay I'll try a 1 line test just in case 
r'\b(.*?([b-df-hj-np-tv-xz])(\2{3,}).*)\b' 
    # Using 'asdfdffff' -> [('asdfdffff', 'f', 'fff')] 
    # Using dictionary -> [] # WAIT WHAT?! 

這最後一個是如何工作的?也許有沒有3+重複輔音字?我在我的學校服務器上使用了/usr/share/dict/cracklib-small,我認爲這個服務器大約有50,000個字。

我仍在努力,但任何建議都會很棒。

我覺得好奇的一件事是,你不能回引用一個非捕獲組。如果我只想輸出完整的單詞,我使用(?:...)來避免捕獲,但是我無法取回參考。很明顯,我可以離開捕捉,循環播放結果和過濾掉額外的東西,但我絕對想用只有正則表達式來解決這個問題!

也許有辦法做非捕獲,但仍然允許回參考?或者也許有一個完全不同的表達,我還沒有測試過。

+0

作業是細問這裏的時候,你有這方面所作的努力:)請分享'['sommmmmword','someworddddd']'而不是'[('sommmmword','mmmmm',...),...]的邏輯'這些兩者的區別是什麼? ? –

+0

啊,是的,抱歉,如果這似乎令人困惑。我進行了編輯。 – spanishgum

+0

1)使用're.findall'獲取所有結果,而不是're.match'(只搜索1個匹配項,只在字符串開始處)。 2)'[b-z && [^ eiou]]'是一個Java/ICU正則表達式,Python're'不支持這種語法。 3)爲了避免使用're.findall'的元組中的「額外」值,*不要*使用捕獲組。如果您需要反向引用,請使用're.finditer'而不是're.findall'並訪問每個匹配的'.group()'。 –

回答

1

這裏有幾點考慮:

  1. 使用re.findall把所有的結果,而不是re.match(僅搜索1個匹配,只有在字符串的開始)。

  2. [b-z&&[^eiou]]是Java/ICU正則表達式,Python re不支持此語法。在Python中,您可以重新定義範圍以跳過元音,或使用(?![eiou])[b-z]

  3. 爲避免元組中帶有re.findall,的元組中的「額外」值,請勿使用使用捕獲組。如果您需要反向引用,請使用re.finditer而不是re.findall並訪問每個匹配的.group()

說回正題,你怎麼可以使用反向引用,仍然獲得了全場比賽,這裏是一個working demo

import re 
s = """someword 
sommmmmeword 
someworddddd 
sooooomeword""" 
res =[x.group() for x in re.finditer(r"\w*([b-df-hj-np-tv-xz])\1\w*", s)] 
print(res) 
# => ['sommmmmeword', 'someworddddd'] 
+0

啊,我正在使用fiindall,我只是誤輸了這個例子。但我沒有嘗試finditer!我認爲這只是findall的一個生成器。一旦我回家,我會試一試!謝謝。另外作爲一個附註,不是明確地說'\ 1 \ 1 \ 1 \ 1 ...'來收集匹配的N個副本,我可以只使用\ 1 {N}而不分組嗎? – spanishgum

+0

您可以使用與反向引用相同的量詞(=量化反向引用),方法與任何原子相同:'\ 1 {4}'。看[這個正則表達式演示](https://regex101.com/r/FU9R61/1)。 –