将未格式化的国内和国际 phone 号码分开

Separate national and international phone numbers that are not formatted

我正在做我的第一个“大”项目,我基本上需要处理很多 phone 数字,比如,从文件中提取它们(已经完成),将它们格式化为相同的格式(问题出在这里),最后将它们存储在数据库中(也已经完成)。
格式化的问题是我无法控制数据源,它们的格式不一致,都是国内和国际号码,有的有加号的国家代码,有的没有,有的有括号,连字符, 前导 0, 等等。有些没有。
我正在尝试使用库 phonenumbers 来分隔国内和国际号码,我的国家是巴西,绝大多数号码都是巴西人。所以我首先删除所有不必要的字符,如括号、连字符、空格、加号和前导零

df['Mobile Phone'] = df['Mobile Phone'].str.replace('\(|\)|\-|\+|\s', '')

df['Mobile Phone'] = df['Mobile Phone'].str[:1].str.replace('0', '') + df['Mobile Phone'].str[1:]

下一步将是将本国人与国际人分开,这就是使用图书馆的地方。到目前为止,我已经尝试了两种方法,但它们都给出了异常错误。 在第一次尝试中,我希望能够用该号码的原产国名称填写原产地列,这样我就可以将产自巴西的号码与其他号码分开。然而,这是不可能的,因为我需要通知 phonenumbers.parse() 该号码的原产国,这是不可能的,因为我无法知道,因此我得到如下错误

df['Origin'] = df['Mobile Phone'].apply(lambda x: geocoder.description_for_number(phonenumbers.parse(x), 'en'))

NumberParseException: (0) Missing or invalid default region.

所以我试图将原产国通知为巴西 (BR),但它也 return 给我一个错误,因为在某些时候传递给 phonenumbers.parse() 的数字将是国际号码,不会被识别为有效号码,如下代码和错误

df['Origin'] = df['Mobile Phone'].apply(lambda x: geocoder.description_for_number(phonenumbers.parse(x, 'BR'), 'en'))

NumberParseException: (1) The string supplied did not seem to be a phone number.

我还尝试使用 phonenumbers.is_valid_number() 并在 'valid' 列中填充 true 或 false 如果该数字对巴西有效,但是错误仍然存​​在,因为当传递phonenumbers.parse() 方法的号码,如果号码是国际号码,它将无法识别并发出错误

df['Valid'] = df['Mobile Phone'].apply(lambda x: phonenumbers.is_valid_number(phonenumbers.parse(x, 'BR')))

NumberParseException: (1) The string supplied did not seem to be a phone number.

是否有任何方法可以避免或忽略这些异常,以便完成其余的检查?或者在调用异常时 return 列的另一个值的某种方式,表明该数字未被识别?或者有没有办法将所有现有国家/地区的列表传递给 phonenumbers.parse() 方法?,像这样

df['Valid'] = df['Mobile Phone'].apply(lambda x: phonenumbers.is_valid_number(phonenumbers.parse(x, list_of_countries)))

df['Valid'] = df['Mobile Phone'].apply(lambda x: phonenumbers.is_valid_number(phonenumbers.parse(x, ['EN', 'GB', 'BR'])))

这是我正在处理的一个文件中包含的一些号码的样本,前 4 个号码是巴西号码,最后一个是国际号码,没有经过任何处理

+55 34 98400-xxxx
34 99658-xxxx
+349798xxxx
9685-xxxx
549215xxxx
+598 91 xxx xxx
+81 80-4250-xxxx
+81 90-4262-xxxx
+971 50 147 xxxx
+972 53-881-xxxx

在我进行清理无用字符的处理后,它们看起来像这样

553498400xxxx
3499658xxxx
349798xxxx
9685xxxx
549215xxxx
59891xxxxxx
81804250xxxx
81904262xxxx
97150147xxxx
97253881xxxx

完整的巴西本地号码是这样的格式:+55 XX XXXXX-XXXX,但是数据中有不完整的号码,没有一些信息,比如国家代码。

我不打算对国际号码执行任何类型的格式化,因为它们是来自几个不同国家的号码,每个都有自己的格式,我只需要以某种方式从数据框中删除它们,以便我可以执行巴西号码的格式,之后我将把国际号码再次放入数据框中,正如我已经说过的,我已经编写了代码来格式化巴西号码,在没有的号码中插入必要的信息,我的困难实际上是如何使用 phone 号码库或其他方式将国际号码与巴西号码分开。

如果您不知道哪些号码是国际号码,哪些是本地号码,您只需要同时尝试:

def guess_phonenumber(clean, loc):
    # Try national
    pn = phonenumbers.parse(clean, loc)
    if not phonenumbers.is_valid_number(pn):
        # Not national; add + and try international
        pn = phonenumbers.parse("+" + clean, None)
    if not phonenumbers.is_valid_number(pn):
        # Not international either
        pn = None
    return pn

guess_phonenumber(clean_phone_number, "BR")
# => PhoneNumber or None

如果 phone 无法识别,它可能完全无效,或者缺少太多信息无法重建(例如本地号码,当您不知道它是哪个区域时是本地的)。