2011-08-09 87 views
2
patterns = {} 
    patterns[1] = re.compile("[A-Z]\d-[A-Z]\d") 
    patterns[2] = re.compile("[A-Z]\d-[A-Z]\d\d") 
    patterns[3] = re.compile("[A-Z]\d\d-[A-Z]\d\d") 
    patterns[4] = re.compile("[A-Z]\d\d-[A-Z]\d\d\d") 
    patterns[5] = re.compile("[A-Z]\d\d\d-[A-Z]\d\d\d") 
    patterns[6] = re.compile("[A-Z][A-Z]\d-[A-Z][A-Z]\d") 
    patterns[7] = re.compile("[A-Z][A-Z]\d-[A-Z][A-Z]\d\d") 
    patterns[8] = re.compile("[A-Z][A-Z]\d\d-[A-Z][A-Z]\d\d") 
    patterns[9] = re.compile("[A-Z][A-Z]\d\d-[A-Z][A-Z]\d\d\d") 
    patterns[10] = re.compile("[A-Z][A-Z]\d\d\d-[A-Z][A-Z]\d\d\d") 

    def matchFound(toSearch): 
     for items in sorted(patterns.keys(), reverse=True): 
      matchObject = patterns[items].search(toSearch) 
      if matchObject: 
       return items 
     return 0 

然後我用下面的代碼來尋找匹配:可能簡化這些Python正則表達式?

 while matchFound(toSearch) > 0: 

我有10個不同的正則表達式,但我覺得他們可以通過一個被替換,寫得好,更優雅的正則表達式。你們認爲這有可能嗎?

編輯:忘了兩個表達式:

patterns[11] = re.compile("[A-Z]\d-[A-Z]\d\d\d") 
    patterns[12] = re.compile("[A-Z][A-Z]\d-[A-Z][A-Z]\d\d\d") 

EDIT2:我結束了以下內容。我意識到我可以得到額外的結果,但我不認爲他們在我分析的數據中是可能的。

patterns = {} 
    patterns[1] = re.compile("[A-Z]{1,2}\d-[A-Z]{1,2}\d{1,3}") 
    patterns[2] = re.compile("[A-Z]{1,2}\d\d-[A-Z]{1,2}\d{2,3}") 
    patterns[3] = re.compile("[A-Z]{1,2}\d\d\d-[A-Z]{1,2}\d\d\d") 
+1

除了。join('|')我假設:P – Andrew

+1

如果你想說「找到與其中任何一個相匹配的東西」,多個正則表達式可以總是被單個正則表達式替換。你的直覺在這裏很好地服務你。證明:使用'|'連接定義正則表達式的字符串字符,你已經構建它。這就是說,在這種情況下,肖恩爲你製作了一個,這進一步簡化了我剛剛解釋的內容。 – Crisfole

+1

實際上並沒有回答你的問題(我相信肖恩已經做過了),我想推薦我使用的小抄。我個人使用正則表達式很少見,這就是爲什麼我總是諮詢這張表格 - http://www.addedbytes.com/cheat-sheets/regular-expressions-cheat-sheet/ - 我覺得它非常有用。只是打印出來,在你的桌子周圍:) – Timur

回答

4

喬什 - 卡斯威爾指出,肖恩光明的答案將匹配比你原來的組更多的投入。對不起,我沒有弄清楚。 (將來可能會更好地闡明你的問題。)

所以你的基本問題是正則表達式不能計數。但我們仍然可以用非常光滑的方式在Python中解決這個問題。首先我們制定一個匹配任何合法投入的模式,但也會匹配一些您想要拒絕的模式。接下來,我們定義一個函數,該函數使用該模式,然後檢查匹配對象,並計數以確保匹配的字符串符合長度要求。

import re 
_s_pat = r'([A-Z]{1,2})(\d{1,3})-([A-Z]{1,2})(\d{1,3})' 
_pat = re.compile(_s_pat) 

_valid_n_len = set([(1,1), (1,2), (1,3), (2,2), (2,3), (3,3)]) 
def check_match(s): 
    m = _pat.search(s) 
    try: 
     a0, n0, a1, n1 = m.groups() 
     if len(a0) != len(a1): 
      return False 
     if not (len(n0), len(n1)) in _valid_n_len: 
      return False 
     return True 
    except (AttributeError, TypeError, ValueError): 
     return False 

下面是對上述代碼的一些解釋。

首先我們使用原始字符串來定義模式,然後我們預編譯模式。我們可以將字符串填充到re.compile()的調用中,但我喜歡有一個單獨的字符串。我們的模式有四個不同的部分用括號括起來;這些將成爲「比賽小組」。有兩個匹配組匹配字母字符,兩個匹配組匹配數字。這一模式將匹配你想要的一切,但不會排除你不想要的東西。

接下來我們聲明一個set,它具有數字的所有有效長度。例如,第一組數字可以是1位數字,第二組可以是2位數字;這是(1,2)(值爲tuple)。集合是一種很好的方式來指定我們想要合法的所有可能的組合,同時仍然能夠快速檢查給定的一對長度是否合法。

函數check_match()首先使用該模式與字符串進行匹配,返回綁定到名稱m的「匹配對象」。如果搜索失敗,m可能設置爲None。我沒有明確測試None,而是使用了try/except塊;回想起來,僅僅測試None可能會更好。對不起,我的意思不是很混亂。但是try/except模塊是一種非常簡單的方式來包裝某些東西並使其非常可靠,所以我經常將它用於這樣的事情。

最後,check_match()將匹配組解包爲四個變量。兩個alpha組是a0和a1,兩個數組分別是n0和n1。然後它檢查長度是合法的。據我所知,規則是阿爾法組需要是相同的長度;然後我們建立一個tuple數字組長度並檢查tuple是否在我們的有效tupleset s中。

這是上面的一個稍微不同的版本。也許你會更喜歡它。

import re 
# match alpha: 1 or 2 capital letters 
_s_pat_a = r'[A-Z]{1,2}' 
# match number: 1-3 digits 
_s_pat_n = r'\d{1,3}' 

# pattern: four match groups: alpha, number, alpha, number 
_s_pat = '(%s)(%s)-(%s)(%s)' % (_s_pat_a, _s_pat_n, _s_pat_a, _s_pat_n) 
_pat = re.compile(_s_pat) 

# set of valid lengths of number groups 
_valid_n_len = set([(1,1), (1,2), (1,3), (2,2), (2,3), (3,3)]) 

def check_match(s): 
    m = _pat.search(s) 
    if not m: 
     return False 
    a0, n0, a1, n1 = m.groups() 
    if len(a0) != len(a1): 
     return False 
    tup = (len(n0), len(n1)) # make tuple of actual lengths 
    if not tup in _valid_n_len: 
     return False 
    return True 

注:它看起來像是有效長度規則其實很簡單:

if len(n0) > len(n1): 
     return False 

如果該規則爲你工作,你可以擺脫集和元組的東西。嗯,我會讓變量名縮短一點。

import re 
# match alpha: 1 or 2 capital letters 
pa = r'[A-Z]{1,2}' 
# match number: 1-3 digits 
pn = r'\d{1,3}' 

# pattern: four match groups: alpha, number, alpha, number 
p = '(%s)(%s)-(%s)(%s)' % (pa, pn, pa, pn) 
_pat = re.compile(p) 

def check_match(s): 
    m = _pat.search(s) 
    if not m: 
     return False 
    a0, n0, a1, n1 = m.groups() 
    if len(a0) != len(a1): 
     return False 
    if len(n0) > len(n1): 
     return False 
    return True 
+0

哦,你比我快一點:-)這正是我的意思。 – glglgl

+0

這看起來不錯,但我不得不承認,我不知道這段代碼是幹什麼的。 編輯:好吧,讀一下代碼後,我想我明白了。我會試一試,謝謝。 – anon58192932

+0

對不起,我不是故意隱瞞的。我會在代碼後添加一些解釋。 – steveha

4

肖恩布萊特給了你你需要的答案。這裏只是一個小技巧:

Python有很棒的文檔。在這種情況下,你可以用「help」命令閱讀:

import re 
help(re) 

如果你通過幫助閱讀,你會看到:

{m,n} Matches from m to n repetitions of the preceding RE. 

它還有助於使用谷歌。 「Python的正則表達式」 發現這些鏈接對我來說:

http://docs.python.org/library/re.html

http://docs.python.org/howto/regex.html

兩者都是值得一讀。

+0

謝謝你的鏈接。我會將它們添加到我的收藏夾中。 – anon58192932

1

建立在肖恩的(現在明顯被刪除)的答案,你可以減少模式的數量。由於數字匹配長度組合的限制(即,如果第一位置爲m,第二位至少爲m且不多於3),我不確定是否可以將其降至一位:

"[A-Z]\d-[A-Z]\d{1,3}" 
"[A-Z]\d\d-[A-Z]\d{2,3}" 
"[A-Z]\d\d\d-[A-Z]\d\d\d" 
"[A-Z][A-Z]\d-[A-Z][A-Z]\d{1,3}" 
"[A-Z][A-Z]\d\d-[A-Z][A-Z]\d{2,3}" 
"[A-Z][A-Z]\d\d\d-[A-Z][A-Z]\d\d\d" 

這使用{m,n}repeat qualifier syntax,它指定緊接在前的匹配重複至少m但不超過n次。您也可以指定一個單號n;那麼比賽必須成功正是n時間:

"[A-Z]{2}\d-[A-Z]{2}\d{2,3}" 
+0

這比我擁有的要好很多。但是它也顯示了我的代碼中的邏輯錯誤。我將編輯該問題。 – anon58192932

3

喬希是對的,至少減少RE的數量。

但是你也可以採取比允許範圍寬的RE,然後再檢查是否滿足所有條件。如

pattern = re.compile("([A-Z]{1,2})(\d{1,3})-([A-Z]{1,2})(\d{1,3})") 

然後

matchObject = pattern.search(toSearch) 
if matchObject and <do something with the length of the groups, comparing them)>: 
    return <stuff> 

但是,即使不工作,由於某種原因,有很多方法可以改善的是:

patterns = tuple(re.compile(r) for r in (
    "[A-Z]\d-[A-Z]\d{1,2}", 
    "[A-Z]\d\d-[A-Z]\d{2,3}", 
    "[A-Z]\d\d\d-[A-Z]\d\d\d", 
    "[A-Z][A-Z]\d-[A-Z][A-Z]\d{1,2}", 
    "[A-Z][A-Z]\d\d-[A-Z][A-Z]\d{2,3}", 
    "[A-Z][A-Z]\d\d\d-[A-Z][A-Z]\d\d\d", 
) 

def matchFound(toSearch): 
    for pat in reversed(patterns): 
     matchObject = pat.search(toSearch) 
     if matchObject: 
      return items # maybe more useful? 
    return None 
從模式