用于修复澳大利亚/新西兰电话号码的Python正则表达式

vic*_*ooi 0 python regex phone-number

我有一个Python脚本,我们用它来解析用户输入的电话号码的CSV文件 - ergo,有很多奇怪的格式/错误.我们需要将这些数字解析为它们各自的组件,以及修复一些常见的条目错误.

我们的电话号码是悉尼或墨尔本(澳大利亚)或奥克兰(新西兰),以国际格式提供.

我们的标准悉尼号码如下:

+61(2)8328-1972
Run Code Online (Sandbox Code Playgroud)

我们有国际前缀+61,后面是括号中的单个数字区号2,后跟本地组件的两半,用连字符分隔8328-1972.

墨尔本数字在区号中只有3而不是2,例如

+61(3)8328-1972
Run Code Online (Sandbox Code Playgroud)

奥克兰的数字相似,但它们有一个7位数的本地组件(3个然后是4个数字),而不是正常的8位数.

+64(9)842-1000
Run Code Online (Sandbox Code Playgroud)

我们还针对一些常见错误进行了匹配.我已将正则表达式分离为自己的类.

class PhoneNumberFormats():
    """Provides compiled regex objects for different phone number formats. We put these in their own class for performance reasons - there's no point recompiling the same pattern for each Employee"""
    standard_format = re.compile(r'^\+(?P<intl_prefix>\d{2})\((?P<area_code>\d)\)(?P<local_first_half>\d{3,4})-(?P<local_second_half>\d{4})')
    extra_zero = re.compile(r'^\+(?P<intl_prefix>\d{2})\(0(?P<area_code>\d)\)(?P<local_first_half>\d{3,4})-(?P<local_second_half>\d{4})')
    missing_hyphen = re.compile(r'^\+(?P<intl_prefix>\d{2})\(0(?P<area_code>\d)\)(?P<local_first_half>\d{3,4})(?P<local_second_half>\d{4})')
    space_instead_of_hyphen = re.compile(r'^\+(?P<intl_prefix>\d{2})\((?P<area_code>\d)\)(?P<local_first_half>\d{3,4}) (?P<local_second_half>\d{4})')
Run Code Online (Sandbox Code Playgroud)

我们有一个用于standard_format数字,其他用于各种常见错误情况,例如在区号之前加一个零(02而不是2), or missing hyphens in the local component (e.g.83281972 instead of8328-1972`)等.

然后我们从级联if/elifs中调用这些:

def clean_phone_number(self):
    """Perform some rudimentary checks and corrections, to make sure numbers are in the right format.
    Numbers should be in the form 0XYYYYYYYY, where X is the area code, and Y is the local number."""
    if not self.telephoneNumber:
        self.PHFull = ''
        self.PHFull_message = 'Missing phone number.'
    else:
        if PhoneNumberFormats.standard_format.search(self.telephoneNumber):
            result = PhoneNumberFormats.standard_format.search(self.telephoneNumber)
            self.PHFull = '0' + result.group('area_code') + result.group('local_first_half') + result.group('local_second_half')
            self.PHFull_message = ''
        elif PhoneNumberFormats.extra_zero.search(self.telephoneNumber):
            result = PhoneNumberFormats.extra_zero.search(self.telephoneNumber)
            self.PHFull = '0' + result.group('area_code') + result.group('local_first_half') + result.group('local_second_half')
            self.PHFull_message = 'Extra zero in area code - ask user to remediate.'
        elif PhoneNumberFormats.missing_hyphen.search(self.telephoneNumber):
            result = PhoneNumberFormats.missing_hyphen.search(self.telephoneNumber)
            self.PHFull = '0' + result.group('area_code') + result.group('local_first_half') + result.group('local_second_half')
            self.PHFull_message = 'Missing hyphen in local component - ask user to remediate.'
        elif PhoneNumberFormats.space_instead_of_hyphen.search(self.telephoneNumber):
            result = PhoneNumberFormats.missing_hyphen.search(self.telephoneNumber)
            self.PHFull = '0' + result.group('area_code') + result.group('local_first_half') + result.group('local_second_half')
            self.PHFull_message = 'Space instead of hyphen in local component - ask user to remediate.'
        else:
            self.PHFull = ''
            self.PHFull_message = 'Number didn\'t match recognised format. Original text is: ' + self.telephoneNumber
Run Code Online (Sandbox Code Playgroud)

我的目标是尽可能地使匹配尽可能紧,但至少还要抓住常见错误.

虽然我上面做了很多问题:

  1. \d{3,4}用来匹配本地组件的前半部分.理想的情况下,但是,我们只有真正想赶上一个3位数的上半年,如果如果它是新西兰数(即开始+64(9)).这样,我们可以标记缺少数字的悉尼/墨尔本数字.我可以将auckland_number分成它自己的正则表达式模式PhoneNumberFormats,但是,这意味着它不会捕获与错误情况相结合的新西兰数字(extra_zero,missing_hyphen,space_instead_of_hyphen).因此,除非我为奥克兰重新创建它们的版本,例如auckland_extra_zero,这似乎是毫无意义的重复,我看不出如何轻松解决这个问题.
  2. 我们不会拾取错误组合 - 例如,如果他们有一个额外的零,并且缺少连字符,我们将不会选择它.有没有一种简单的方法可以使用正则表达式,而无需显式创建不同错误的排列?

我想解决上面两个问题,并希望收紧一点,抓住我错过的任何东西.是否有更聪明的方法来做我上面尝试过的事情?

干杯,维克多

附加评论:

以下仅提供一些上下文:

这个脚本适用于一家全球性公司,其中一个办公室位于悉尼,一个位于墨尔本,一个位于奥克兰.

这些数字来自员工的内部Active Directory列表(即,它不是客户列表,而是我们自己的办公室电话).

因此,我们不是在寻找一般的澳大利亚电话号码匹配脚本,相反,我们正在寻找一个普通的sript解析来自三个特定办公室的数字.一般来说,只有最后4个数字应该有所不同.

不需要手机.

该脚本旨在解析Active Directory的CSV转储,并将数字重新格式化为另一个程序的可接受格式(QuickComm)

这个程序来自外部供应商,需要我在上面的代码中生成的确切格式的数字 - 这就是为什么这些数字像0283433422一样吐出来的原因.

我编写的脚本无法更改记录,它只适用于它们的CSV转储 - 记录存储在Active Directory中,访问它们以解决它们的唯一方法是通过电子邮件发送给员工并询问他们登录并更改自己的记录.

所以这个脚本由PA运行,以产生该程序所需的输出.她/他还将获得数字格式不正确的人员列表 - 因此有关要求用户进行修复的消息.从理论上讲,应该只有少数这些.然后,我们通过电子邮件发送/响铃这些员工,要求他们修改他们的记录 - 脚本每月运行一次(数字可能会更改),我们还需要标记新员工,这些员工也设法输入错误的记录.

@John Macklin:你是否推荐我废弃正则表达式,并尝试从字符串中提取特定位置的数字?

我正在寻找一种方法来捕捉常见的错误情况,组合(例如空格而不是连字符,加上额外的零),但这不容易实现吗?

Joh*_*hin 5

不要使用复杂的正则表达式.删除除数字以外的所有内容 - 非数字是容易出错的数字.如果第三个数字为0,则将其删除.预期61后跟有效的AUS区号([23478],一般性NB 4用于移动设备),然后是8位数或64位,后跟有效的NZL区号(无论是什么),后跟7位数.还有别的坏事.在好东西中,在适当的位置插入+() - .

顺便说一句(1)区号2是整个NSW + ACT,不仅仅是悉尼,3是VIC + TAS(2)这些天很多人没有固定电话,只有手机,人们倾向于保留相同的手机号码比他们保持相同的固定电话号码或相同的邮政地址更长,因此手机号码非常适合模糊匹配客户记录 - 所以我有点好奇为什么你不包括它们.

以下内容将告诉您有关澳大利亚新西兰电话编号方案的所有信息,以及更多内容.

评论正则表达式:

(1)您正在使用带有"^"前缀的搜索方法.使用没有前缀的匹配方法稍微不那么优雅.

(2)您似乎没有检查电话号码字段中的尾随垃圾:

>>> import re
>>> standard_format = re.compile(r'^\+(?P<intl_prefix>\d{2})\((?P<area_code>\d)\
)(?P<local_first_half>\d{3,4})-(?P<local_second_half>\d{4})')
>>> m =standard_format.search("+61(3)1234-567890whoopsie")
>>> m.groups()
('61', '3', '1234', '5678')
>>>
Run Code Online (Sandbox Code Playgroud)

你可能希望(a)用\ Z(NOT $ )结束你的一些正则表达式,这样当它们有尾随垃圾时它们就不匹配或者(b)引入另一个组来捕获尾随垃圾.

社会工程评论:你是否测试了用户对执行该指令的工作人员的反应:"本地组件中的空格而不是连字符 - 要求用户进行修复"?脚本不能修复它并继续吗?

以及对代码的一些评论:

self.PHFull代码

(a)非常重复(如果你必须有正则表达式将它们放在一个带有相应的动作代码和错误消息的列表中并迭代列表)

(b)对于"错误"情况与标准情况相同(那么为什么要求用户"修复"???)

(c)丢弃国家代码并替换为0,即您的标准+61(2)1234-5678被保留为0212345678 aarrgghhh ...即使您的国家存储的地址如果NZer迁移到的地址也不好Aus和地址得到更新,但没有电话号码,请不要说你依赖当前(奥克兰地区以外没有新西兰客户???)区域代码不重叠...

全文揭晓后更新

为您和员工保持简单.使用Active Directory的工作人员的说明应该(取决于哪个办公室)"填写+61(2)9876-7后跟您的3位分机号码".如果他们在几次尝试后无法做到这一点,那么他们就得到了DCM.

因此,每个办公室使用一个正则表达式,填写常量部分,以便说SYD办公室具有+61(2)9876-7ddd您使用正则表达式的数字r"\+61\(2\)9876-7\d{3,3}\Z".如果正则表达式匹配,则删除所有非数字并"0" + the_digits[2:]用于下一个应用程序.如果没有正则表达式匹配,请发送火箭.