2008-12-22 59 views
2

我正在處理一段代碼,將手機號碼變爲手機鏈接 - 我已經知道了,但感覺真的很髒。電話號碼到Python中的鏈接

import re 
from string import digits 

PHONE_RE = re.compile('([(]{0,1}[2-9]\d{2}[)]{0,1}[-_. ]{0,1}[2-9]\d{2}[-_. ]{0,1}\d{4})') 

def numbers2links(s): 
    result = "" 
    last_match_index = 0 
    for match in PHONE_RE.finditer(s): 
      raw_number = match.group() 
      number = ''.join(d for d in raw_number if d in digits) 
      call = '<a href="tel:%s">%s</a>' % (number, raw_number) 
      result += s[last_match_index:match.start()] + call 
      last_match_index = match.end() 
    result += s[last_match_index:] 
    return result 

>>> numbers2links("Ghost Busters at (555) 423-2368! How about this one: 555 456 7890! 555-456-7893 is where its at.") 
'Ghost Busters at <a href="tel:5554232368">(555) 423-2368</a>! How about this one: <a href="tel:5554567890">555 456 7890</a>! <a href="tel:5554567893">555-456-7893</a> is where its at.' 

反正我有可能重組正則表達式或我使用,使這種清潔的正則表達式的方法?

更新

爲了澄清,我的問題是不是我的正則表達式的正確性 - 我意識到,這是有限的。相反,我想知道是否有人對替代電話號碼鏈接的方法有任何意見 - 無論如何,我可以使用re.replace或類似的東西,而不是我有的字符串hackery?

回答

5

不錯第一次:)我認爲這個版本更具可讀性(可能更快一點)。這裏要注意的關鍵是使用re.sub。讓我們從討厭匹配索引了......

import re 

PHONE_RE = re.compile('([(]{0,1}[2-9]\d{2}[)]{0,1}[-_. ]{0,1}[2-9]\d{2}[-_. ]{0,1}\d{4})') 
NON_NUMERIC = re.compile('\D') 

def numbers2links(s): 

    def makelink(mo): 
     raw_number = mo.group() 
     number = NON_NUMERIC.sub("", raw_number) 
     return '<a href="tel:%s">%s</a>' % (number, raw_number) 

    return PHONE_RE.sub(makelink, s) 


print numbers2links("Ghost Busters at (555) 423-2368! How about this one: 555 456 7890! 555-456-7893 is where its at.") 

的注意事項:在我的實踐中,我沒有發現太大的加速的預編譯簡單的正則表達式就像兩個我使用,即使你正在使用它們數千次。重新模塊可能有某種內部緩存 - 不費心讀取源代碼並進行檢查。

此外,我替換了檢查每個字符的方法,看看它是否在string.digits與另一個re.sub(),因爲我認爲我的版本更具可讀性,並不是因爲我確信它的性能更好(儘管可能)。

+0

這是約100倍更清晰 - 謝謝三聯! – 2008-12-22 21:14:55

0

幾件事情,將清理現有的正則表達式沒有真正改變功能:

替換{0,1}用,[(]用([)用)。你也可以只是製作你的[2-9],因此你可以讓這些模式成爲最後一部分的\ d {3}和\ d {4}。我懷疑這會真的增加誤報率。

0

爲什麼不重複使用別人的作品 - 例如,從RegExpLib.com

我的第二個建議是記住除美國之外還有其他國家,其中不少國家都有電話;-)請在我們的軟件開發過程中不要忘記我們。

另外,還有格式化電話號碼的標準;國際電聯的E.123。我對標準的回憶是它所描述的與常用的用法不匹配。

編輯:我混淆了G.123和E.123。哎呀。道具Bortzmeyer

1

您的正則表達式僅解析特定的格式,這不是國際標準。如果你只限於一個國家,它可能會奏效。

否則,國際標準是ITU E.123:「符號爲國內和國際電話號碼, 電子郵件地址和網絡地址」

1

首先,可靠地獲取電話號碼與一個正則表達式是出了名的難不可能的強烈傾向。並非每個國家都對「電話號碼」的定義與美國一樣窄,即使在美國也是如此。,事情複雜得多,他們似乎(從Wikipedia article on the North American Numbering Plan):

  • A)國家代碼:可選的前綴( 「1」 或 「1」 或 「001」)
    • ((00|\+)?1)?
  • B)編號計劃區代碼(NPA):不能從1開始,數字2不能是9
    • [2-9][0-8][0-9]
  • C)交換碼(NXX):不能從1開始,不能以 「11」 結尾,可選圓括號
    • \(?[2-9](00|[2-9]{2})\)?
  • d)站代碼:四位數字,不能全部爲0 (我想)
    • (?!0{4})\d{4}
  • E)的可選擴展可遵循
    • ([x#-]\d+)?
  • S)的數量是空格,虛線,點(或不)
    • [. -]?

所以,基本的正則表達式分離對於美國將是:

((00|\+)?1[. -]?)?\(?[2-9][0-8][0-9]\)?[. -]?[2-9](00|[2-9]{2})[. -]?(?!0{4})\d{4}([. -]?[x#-]\d+)? 
| A  |S | | B    | S | C    | S | D   | S | E  | 

而這僅僅是美國相對微不足道的編號計劃,即使在那裏它也沒有涵蓋所有的細節。如果你想讓它可靠,你必須爲所有預期的輸入語言開發一個類似的野獸。