【问题标题】:Python 3 replace part of string with data from dictPython 3 用 dict 中的数据替换部分字符串
【发布时间】:2018-02-14 03:41:38
【问题描述】:

我需要将电话号码转换为国际格式。我有一个电话号码示例列表

rows = [
  (datetime.time(20, 35, 30), '0707262078',),
  (datetime.time(20, 38, 18), '+46706332602',),
  (datetime.time(20, 56, 35), '065017063'),
  (datetime.time(21, 45, 1), '+46730522807',),
  (datetime.time(22, 13, 47), '0046733165812')
]

我需要将所有以 ex 07 开头的数字替换为 +467,将所有 06 替换为 +466,将 00 替换为 +。对于上面的示例,我需要将号码转为 0707262078 到 +46707262078、065017063 到 +4665017063 和 0046733165812 到 +46733165812。
不知道是否可以仅在正则表达式中执行此操作,或者我是否需要使用其他代码执行此操作。

一直在尝试将 re.sub 与 lamda 结合使用,我的想法是制作一个带有匹配替换的字典,如下所示:

repl_dict = {
  '01': '+461',
  '02': '+462',
  '03': '+463',
  '04': '+464',
  '05': '+465',
  '06': '+466',
  '07': '+467',
  '08': '+468',
  '09': '+469',
  '00': '+'
}

到目前为止我的尝试:

import re
rows = [
  (datetime.time(20, 35, 30), '0707262078',),
  (datetime.time(20, 38, 18), '+46706332602Ring via Mitel ',),
  (datetime.time(20, 56, 35), '065017063'),
  (datetime.time(21, 45, 1), '+46730522807Ring via Mitel ',),
  (datetime.time(22, 13, 47), '0046733165812')
]

repl_dict = {
  '01': '+461',
  '02': '+462',
  '03': '+463',
  '04': '+464',
  '05': '+465',
  '06': '+466',
  '07': '+467',
  '08': '+468',
  '09': '+469',
  '00': '+'
}

for row in rows:
    regex = re.compile(r'^\d{1}[0-9](\d*)'), re.S
    DialedNumber = regex.sub(lambda match: repl_dict.get(match.group(0), row[1]), row[1], row[1])  

【问题讨论】:

  • 我可以注意到你的 for 循环没有正确缩进。先解决这个问题(可能只是复制和粘贴错误)。

标签: regex python-3.x


【解决方案1】:

您的正则表达式以\d* 结尾,将匹配整个数字,因此在字典中找不到条目。此外,在对 sub 的调用中似乎有一个无与伦比的括号和一个太多的 row[1]

您可以将正则表达式简化为^00?,将替换字典简化为{'00': '+', '0': '+46'}。这将检查数字是否以一个或两个0 开头,从而使替换字典更加简单且重复性更少。

rows = [(datetime.time(20, 35, 30), '0707262078',), (datetime.time(20, 38, 18), '+46706332602Ring via Mitel ',), (datetime.time(20, 56, 35), '065017063'), (datetime.time(21, 45, 1), '+46730522807Ring via Mitel ',), (datetime.time(22, 13, 47), '0046733165812')]
repl_dict = {'00': '+', '0': '+46'}
regex = re.compile(r'^00?')
for date, number in rows:
    print(regex.sub(lambda match: repl_dict.get(match.group(0)), number))

输出:

+46707262078
+46706332602Ring via Mitel 
+4665017063
+46730522807Ring via Mitel 
+46733165812

如果您只想要数字部分,您可以使用第二个正则表达式(如 [0-9+]*)对数字进行预处理或后处理。

【讨论】:

  • [(tm, re.sub('^(00|0)', lambda m: {'00': '+', '0': '+46'}[m.group(0)], ph)) for (tm, ph) in rows] (诚然,将其设置为单线确实会使其不那么好,但是您将模式和替换字典都缩短了很多,以至于我想展示它。)
【解决方案2】:

这是您问题中给出的基于repl_dict 的幼稚方法。

def repl(match): 
    return repl_dict[match.group(0)]

pat = '^(' + '|'.join(repl_dict) + ')'
new_rows = [(tm, re.sub(pat, repl, ph)) for (tm, ph) in rows]

tobias_k 的回答通过改进您的 repl_dict 和模式提供了更好的方法。

【讨论】:

    【解决方案3】:

    正则表达式^[0-9]{2}

    详情:

    • ^ 在行首断言位置
    • [] 匹配列表中存在的单个字符
    • {n} 完全匹配 n

    Python 代码

    通过@tobias_k,您可以使用repl_dict.get(m.group(), m.group()) 代替repl_dict.get(m.group()) or m.group()

    regex = re.compile(r'^[0-9]{2}')
    
    for i in range(len(rows)):
        rows[i] = (rows[i][0], regex.sub(lambda m: repl_dict.get(m.group()) or m.group(), rows[i][1]))
    

    输出:

    [(datetime.time(20, 35, 30), '+46707262078'), (datetime.time(20, 38, 18), '+46706332602Ring via Mitel '), (datetime.time(20, 56, 35), '+4665017063'), (datetime.time(21, 45, 1), '+46730522807Ring via Mitel '), (datetime.time(22, 13, 47), '+46733165812')]
    

    Code demo

    【讨论】:

    • 如果由于某种原因有数字以非 0 开头的数字,这可能会失败。例如,如果数字是“12345”,则 get 返回 None 并且您结束最多“345”
    • @tobias_k 已修复!
    • 您也可以使用repl_dict.get(m.group(), m.group()),即使用匹配组本身作为默认值。
    【解决方案4】:

    你可以在没有正则表达式的情况下做到这一点:

    for row in rows:
      for repl in repl_dict:
        if row[1].startswith(repl):
          print repl_dict[repl]+row[1][len(repl):]
          break
    

    【讨论】:

      猜你喜欢
      • 2021-08-24
      • 1970-01-01
      • 2021-10-02
      • 2012-12-30
      • 1970-01-01
      • 1970-01-01
      • 2021-10-20
      • 2018-01-22
      • 2012-04-19
      相关资源
      最近更新 更多