在 python 中替换不同长度的数字 (re.sub)

Substituting numbers of different lengths (re.sub) in python

corpus = """In the US 555-0198 and 1-206-5705-0100 are examples fictitious numbers.
            In the UK, 044-113-496-1834 is a fictitious number.
            In Ireland, the number 353-020-917-1234 is fictitious.
            And in Australia, 061-970-654-321 is a fictitious number.
            311 is a joke."""

我是 python 的新手,正在研究正则表达式,试图将所有 7、11、12 和 13 位数字更改为零。我希望它看起来仍然像一个 phone 数字。例如,将 555-0198 更改为 000-0000.Is 有没有办法让 311 保持原样而不变为零?以下是我能想到的

起初我尝试过,但它使所有数字都变成了零

    for word in corpus.split():
        nums = re.sub("(\d)", "0",word)
        print(nums)

然后我尝试了,但我意识到这样做对于 11 位和 13 位数字是不正确的

    def sub_nums():
        for word in corpus.split():
           nums = re.sub("(\d{1,4})-+(\d{1,4})", "000-0000",word)
           print(nums)
    sub_nums()

我认为使用模式首先匹配由连字符分隔的数字然后检查匹配中的数字数是否等于 7、11、12 或 13 可能更容易。

例如,匹配由连字符分隔的数字:

(?<!\S)\d{1,4}(?:-\d{1,4})+(?!\S)
  • (?<!\S) 负向回顾,断言左边的不是非空白字符
  • \d{1,4}匹配1-4位数字
  • (?:-\d{1,4})+ 重复 1+ 次匹配 - 和 1-4 位数字
  • (?!\S) 否定前瞻,断言右边的不是非空白字符

Regex demo | Python demo

示例 Python 使用 re.sub 和 lambda

的代码
import re

regex = r"(?<!\S)\d{1,4}(?:-\d{1,4})+(?!\S)"

test_str = ("In the US 555-0198 and 1-206-5705-0100 are examples fictitious numbers.\n"
            "            In the UK, 044-113-496-1834 is a fictitious number.\n"
            "            In Ireland, the number 353-020-917-1234 is fictitious.\n"
            "            And in Australia, 061-970-654-321 is a fictitious number.\n"
            "            311 is a joke.")

result = re.sub(
    regex,
    lambda x: re.sub(r'\d', '0', x.group())
    if len(x.group().replace('-', '')) in (7, 11, 12, 13) else x.group(), test_str
)

print(result)

输出

In the US 000-0000 and 0-000-0000-0000 are examples fictitious numbers.
            In the UK, 000-000-000-0000 is a fictitious number.
            In Ireland, the number 000-000-000-0000 is fictitious.
            And in Australia, 000-000-000-000 is a fictitious number.
            311 is a joke.

我使用的正则表达式是:

r'(?<!\S)(?:(?=(-*\d-*){7}(\s|\Z))[\d-]+|(?=(-*\d-*){11}(\s|\Z))[\d-]+|(?=(-*\d-*){12}(\s|\Z))[\d-]+|(?=(-*\d-*){13}(\s|\Z))[\d-]+)'

7、11、12 和 13 位数字 phone 号码有一个重复的 "theme" 或模式,所以我将只解释 7 位数字 phone 号码的模式:

  1. (?!\S) 这是一个适用于所有模式的 负面回顾 并表示 phone 数字必须 而不是 前面是 白色字符 space。这是一个双重否定 almost 等同于说 phone 数字前面必须有白色 space 但允许 phone 数字是前面是字符串的开头。另一种方法是等效的 positive lookbehind (?=\s|\A),它表示 phone 数字前面必须有白色 space 字符串的开头。然而,这是一个可变长度的 lookbehind,它在 Python 附带的正则表达式引擎中不受支持(但 PyPi 存储库中的 regex 包支持)。
  2. (?=(-*\d-*){7}(\s|\Z)) 7 位数字 phone 的 lookahead 要求表示下一个字符必须由数字和连字符的某种组合组成,后跟任何一个白色 space 或字符串结尾 数字必须正好是 7.
  3. [\d-]+ 这会实际匹配输入中的下一个数字和连字符。

See Regex Demo

import re


corpus = """In the US 555-0198 and 1-206-5705-0100 are examples fictitious numbers.
            In the UK, 044-113-496-1834 is a fictitious number.
            In Ireland, the number 353-020-917-1234 is fictitious.
            And in Australia, 061-970-654-321 is a fictitious number.
            311 is a joke."""

regex = r'(?<!\S)(?:(?=(-*\d-*){7}(\s|\Z))[\d-]+|(?=(-*\d-*){11}(\s|\Z))[\d-]+|(?=(-*\d-*){12}(\s|\Z))[\d-]+|(?=(-*\d-*){13}(\s|\Z))[\d-]+)'
new_corpus = re.sub(regex, lambda m: re.sub(r'\d', '0', m[0]), corpus)
print(new_corpus)

打印:

In the US 000-0000 and 0-000-0000-0000 are examples fictitious numbers.
            In the UK, 000-000-000-0000 is a fictitious number.
            In Ireland, the number 000-000-000-0000 is fictitious.
            And in Australia, 000-000-000-000 is a fictitious number.
            311 is a joke.