我正在编写一段代码,将电话号码转换为手机的链接 - 我已经得到它,但感觉真的很脏。

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 或者类似的东西而不是我拥有的字符串黑客?

有帮助吗?

解决方案

尼斯先取:)我觉得这个版本是更可读一点(也可能一个却有点快)。这里要注意的关键是使用应用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()因为我觉得我的版本是更具可读性,而不是因为我敢肯定它的性能会更好(尽管它可能)的方法。

其他提示

您正则表达式仅解析特定的格式,它是不是国际标准。如果你限制自己的一个国家,它可能工作。

否则,国际标准是 ITU E.123 “符号的国家和国际电话号码, 电子邮件地址和网络地址“

首先,用单个正则表达式可靠地捕获电话号码是众所周知的困难,而且很可能是不可能的。并非每个国家/地区对“电话号码”的定义都像美国那样狭窄。即使在美国,事情也比看起来更复杂(来自 关于北美编号计划的维基百科文章):

  • 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      |

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

几件事情,将清理现有的正则表达式没有真正改变功能:

替换{0,1}与?,[(]与([)]用)。你也可能也只是让你的[2-9] Bé一个\ d为好,这样可以使这些模式是\ d {3}和\ d {4}最后一部分。我怀疑它真的会增加误报率。

为什么不能重新使用他人的工作 - 例如,从 RegExpLib.com

我的第二个建议是要记住有除了美国和其他国家,还有相当一部分人有电话;-)请您的软件开发过程中,不要忘记我们。

此外,对于电话号码的格式标准; ITU的 E.123 。我的标准的回忆是,它描述了不普遍使用匹配良好。

编辑:我混合起来G.123和E.123。哎呀。道具 Bortzmeyer做了大量

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top