2011-04-19 96 views
7

我有一大組真實世界的文本,我需要將單詞輸出到拼寫檢查器中。我想提取儘可能多的有意義的單詞儘可能沒有太多的噪音。我知道這裏有很多正則表達式的忍者,所以希望有人能幫助我。提取整個單詞

目前我用'[a-z]+'提取所有的字母順序。這是一個好的近似值,但它拖拽了很多垃圾。

理想我想一些正則表達式(並不一定是相當的或有效的)提取的天然單詞分隔符(如[/-_,.: ]等)分隔的所有字母序列,而忽略與非法界限的任何字母序列。

但是我也很高興能夠得到所有不與數字相鄰的字母序列。因此,例如'pie21'將不提取'pie',但'http://foo.com'將提取['http', 'foo', 'com']

我試圖lookaheadlookbehind斷言,但他們採用每個字符(因此,例如,re.findall('(?<!\d)[a-z]+(?!\d)', 'pie21')將返回'pi'時,我想這回沒有)。我嘗試將alpha部分作爲術語來包裝((?:[a-z]+)),但它沒有幫助。

更多細節:的數據是電子郵件數據庫,所以它主要是簡單的英語與正常的數字,但偶爾也有像GIHQ4NWL0S5SCGBDD40ZXE5IDP13TYNEAAC7A21C0垃圾串,我想完全忽略。我假設任何按字母順序排列的數字都是垃圾。

+0

更好地使用原始字符串和正則表達式。 '\ d'碰巧工作,但其他轉義序列將失敗,這可能很難調試。 – 2011-04-19 14:30:34

回答

16

如果你限制自己ASCII字母,然後使用(與re.I選項)

\b[a-z]+\b 

\b是一個字邊界錨,只在字母數字「話」的開頭和結尾。因此\b[a-z]+\b匹配pie,但不匹配pie2121pie

中,也允許其他非ASCII字符,你可以使用這樣的事情:

\b[^\W\d_]+\b 

這也讓重音符號等,您可能需要使用Python 2時設置re.UNICODE選擇,特別是,在爲了使簡寫\w與非ASCII字母匹配。

[^\W\d_]作爲否定字符類允許除數字和下劃線之外的任何字母數字字符。

+0

這聽起來完全像我想要的,但我無法讓bally'\ b's工作。將'text'設置爲一些正常的句子,'re.findall('\ b [a-z] + \ b',text,re.I)'什麼也不返回。不管我放在方括號內(或使用「搜索」或「匹配」),它似乎也沒有幫助。使用'\ B'會得到一些結果,但是會去掉每個單詞的第一個和最後一個字符。儘管聽起來很慵懶,但我現在太累了,無法提出一個新的概念;你知道爲什麼它不起作用嗎?或者你可以在這種情況下發布你如何使用它的文字示例? – orlade 2011-04-19 15:09:29

+4

這就是*完全*爲什麼我給你的問題寫了我的評論。如果你不使用原始字符串('r「\ b [a-z] \ b」'),那麼'\ b'將被解釋爲退格字符。 – 2011-04-19 17:35:20

+0

Ooooooooooooh,這就是你的意思:)。對不起,現在已經是凌晨5點半了,我永遠不會建立這種聯繫。只需添加r,它就可以成爲一種享受!謝謝你,先生。 – orlade 2011-04-19 19:30:01

3

您是否熟悉word boundaries?\b)。您可以提取字的使用順序圍繞\b並在匹配字母:

\b([a-zA-Z]+)\b 

例如,這會搶完整的單詞,但在令牌如連字符,句號,分號等停止

您可以將\b序列,和其他人,過在python manual

編輯另外,如果你正在尋找有關數以下或比賽前,你可以使用負前瞻/背後:

(?!\d) # negative look-ahead for numbers 
(?<!\d) # negative look-behind for numbers 
+0

根據Tim的回答,'\ b'聽起來像我想要的,但它不是很好玩。有任何想法嗎?我之前嘗試過向前看和向後看,但他們似乎將所有角色匹配到與數字相鄰的角色,因此不要完全忽略帶有數字的單詞。此外,它還抱怨需要固定寬度模式的lookahead與那裏的那些+。 – orlade 2011-04-19 15:13:02

+0

@ Pie21:然後只使用一位數的匹配。我們不在乎有多少數字在它之後/之前,只是有一個數字。 [示例](http://re.dabase.com/webre.py?input=pie21+21pie+21pie21+pie®ex=\b%28%3F%3C!\d%29%28 [A-ZA-Z] %2B%29%28%3F!\ d%29 \ b) – 2011-04-19 15:21:35

+0

我得到了這個工作[re.findall(r「\ b([a-zA-Z] +)\ b」,content,re.I) ]但它似乎並沒有向前和反斜線剔除。這裏有一些字出來:'[endif]','$','8','/ small','/ li' – Bill 2015-07-09 05:46:46

2

什麼:

import re 
yourString="pie 42 http://foo.com GIHQ4NWL0S5SCGBDD40ZXE5IDP13TYNEA pie42" 
filter (lambda x:re.match("^[a-zA-Z]+$",x),[x for x in set(re.split("[\s:/,.:]",yourString))]) 

需要注意的是:

  • 分裂爆炸您的字符串轉換成潛在候選=>返回的「電位,詞語」一個列表
  • 集使單一性濾波=>轉換成在組列表中,從而消除出現一次以上的條目。這一步不是強制性的。
  • 過濾器減少了候選人的數量:獲取一個列表,將測試函數應用於每個元素,並返回測試成功的元素列表。在我們的例子中,測試功能是「匿名」
  • 拉姆達:匿名函數,採取一個項目,並檢查它是否是一個字(大寫或小寫字母只)

編輯:增加了一些解釋

+6

我的眼睛!這幾乎看起來像Perl!哦,人道...... – 2011-04-19 14:50:40

+0

這就是爲什麼它很美 – Bruce 2011-04-19 14:57:43

+0

醜陋,它確實有效!乾杯!但是我可以再問一個好處:因爲我不會說lambda或過濾器,有沒有辦法用're.finditer()'來做這種事?我需要跟蹤文本中每個比賽的開始和結束索引。 – orlade 2011-04-19 15:04:20

0

示例代碼

print re.search(ur'(?u)ривет\b', ur'Привет') 
print re.search(ur'(?u)\bривет\b', ur'Привет') 

s = ur"abcd ААБВ" 
import re 
rx1 = re.compile(ur"(?u)АБВ") 
rx2 = re.compile(ur"(?u)АБВ\b") 
rx3 = re.compile(ur"(?u)\bАБВ\b") 
print rx1.findall(s) 
print rx2.findall(s) 
print rx3.findall(s)