Python 中的电话号码链接
-
23-08-2019 - |
题
我正在编写一段代码,将电话号码转换为手机的链接 - 我已经得到它,但感觉真的很脏。
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()
因为我觉得我的版本是更具可读性,而不是因为我敢肯定它的性能会更好(尽管它可能)的方法。
其他提示
您正则表达式仅解析特定的格式,它是不是国际标准。如果你限制自己的一个国家,它可能工作。
首先,用单个正则表达式可靠地捕获电话号码是众所周知的困难,而且很可能是不可能的。并非每个国家/地区对“电话号码”的定义都像美国那样狭窄。即使在美国,事情也比看起来更复杂(来自 关于北美编号计划的维基百科文章):
- 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做了大量