【问题标题】:US-format phone numbers to links in Python美国格式的电话号码到 Python 中的链接
【发布时间】:2008-12-22 05:44:41
【问题描述】:

我正在编写一段代码来将电话号码转换为手机链接 - 我知道了,但感觉真的很脏。

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.'

无论如何我可以重组正则表达式或我正在使用的正则表达式方法以使其更清洁吗?

更新

澄清一下,我的问题不在于我的正则表达式的正确性——我意识到它是有限的。相反,我想知道是否有人对用链接替换电话号码的方法有任何 cmets - 无论如何我可以使用re.replace 或类似的东西来代替我拥有的字符串hackery?

【问题讨论】:

    标签: python regex mobile-website phone-number


    【解决方案1】:

    很好的第一次尝试 :) 我认为这个版本更具可读性(并且可能快一点)。这里要注意的关键是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 模块可能有某种内部缓存 - 没有费心去阅读源代码和检查。

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

    【讨论】:

    • 很高兴能帮上忙 :) 我花了很多个晚上都在为 python re 模块的细节哭泣。很高兴为别人省了一点痛苦。
    【解决方案2】:

    您的正则表达式仅解析特定格式,这不是国际标准。如果您将自己限制在一个国家/地区,它可能会奏效。

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

    【讨论】:

      【解决方案3】:

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

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

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

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

      【讨论】:

        【解决方案4】:

        首先,使用单个正则表达式可靠地捕获电话号码是出了名的困难,而且很有可能是不可能的。并非每个国家/地区对“电话号码”的定义都像美国那样狭窄。即使在美国,事情也比看起来要复杂得多(来自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      |
        

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

        【讨论】:

          【解决方案5】:

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

          将 {0,1} 替换为 ?,将 [(] 替换为 (,[)] 替换为 )。你也可以让你的 [2-9] 也成为 \d ,这样你就可以让这些模式成为最后一部分的 \d{3} 和 \d{4} 。我怀疑它真的会增加误报率。

          【讨论】:

            猜你喜欢
            • 2011-08-16
            • 2010-10-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-05-22
            • 2015-01-19
            • 1970-01-01
            • 2021-11-10
            相关资源
            最近更新 更多