电话号码到Python中的链接

时间:2008-12-22 05:44:41

标签: python regex mobile-website phone-number

我正在编写一段代码,将手机号码转换成手机链接 - 我已经知道了,但感觉很脏。

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 个答案:

答案 0 :(得分: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.")

注意:在我的练习中,我没有注意到加速预编译简单的正则表达式,就像我正在使用的两个,即使你使用它们数千次。 re模块可能有某种内部缓存 - 没有费心阅读源并检查。

此外,我更换了检查每个字符的方法,以查看它是否在string.digits与另一个re.sub(),因为我认为我的版本更具可读性,而不是因为我确定它的效果更好(尽管它可能)。

答案 1 :(得分:1)

您的正则表达式仅解析特定格式,这不是国际标准。如果你将自己局限于一个国家,它可能会有用。

否则,国际标准为ITU E.123:“国内和国际电话号码的表示法, 电子邮件地址和网址“

答案 2 :(得分: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      |

这仅仅是针对美国相对微不足道的编号计划,即便如此,它肯定也没有涵盖所有细微之处。如果你想让它变得可靠,你必须为所有预期的输入语言开发一个类似的野兽。

答案 3 :(得分:0)

在不改变功能的情况下清理现有正则表达式的一些事情:

用{,[(]和(,[]]替换{0,1}。您也可以将[2-9]设置为\ d,因此您可以将这些模式设为\ d {3}和\ d {4}作为最后一部分。我怀疑它会真正提高误报率。

答案 4 :(得分:0)

为什么不重复使用他人的工作 - 例如,来自RegExpLib.com

我的第二个建议是要记住除了美国之外还有其他国家,其中不少有电话;-)请不要忘记我们的软件开发过程。

此外,还有一个电话号码格式的标准;国际电联的E.123。我对标准的回忆是它描述的内容与流行的用法不相符。

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