Регулярное выражение Python для исправления номеров телефонов в Австралии / Новой Зеландии - PullRequest
0 голосов
/ 07 июля 2010

У меня есть сценарий Python, который мы используем для анализа файлов CSV с введенными пользователем номерами телефонов, поэтому существует довольно много странных форматов / ошибок.Нам нужно разбить эти номера на отдельные компоненты, а также исправить некоторые распространенные ошибки при вводе.

Наши номера телефонов указаны для Сиднея, Мельбурна (Австралия) или Окленда (Новая Зеландия), указанных в международном формате.

Наш стандартный номер в Сиднее выглядит следующим образом:

+61(2)8328-1972

У нас есть международный префикс +61, за которым следует код области из одной цифры в скобках, 2, за которыми следуют две половинылокального компонента, разделенного дефисом, 8328-1972.

Мельбурнские цифры просто имеют 3 вместо 2 в коде города, например

+61(3)8328-1972

Оклендские числа похожи, ноони содержат 7-значный локальный компонент (3, а затем 4 цифры) вместо обычных 8 цифр.

+64(9)842-1000

У нас также есть совпадения для ряда распространенных ошибок.Я разделил выражения регулярных выражений на их собственный класс.

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})')

У нас есть одно для чисел standard_format, затем другие для различных распространенных случаев ошибок, например, добавление дополнительного нуля перед кодом области (02 вместо2), or missing hyphens in the local component (e.g. 83281972 instead of 8328-1972`) и т. Д.

Затем мы вызываем их каскадно, если / 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

Моя цель - сделать сопоставление как можно более тесным, но все же, по крайней мере, выявляем типичные ошибки.

Существует ряд проблем с тем, что я сделал выше:

  1. Я использую \d{3,4}, чтобы соответствовать первомуполовина местного компонента.В идеале, однако, мы действительно хотим поймать 3-значную первую половину , если , если это новозеландский номер (т.е. начинается с +64(9)).Таким образом, мы можем пометить номера в Сиднее / Мельбурне, в которых отсутствует цифра.Я мог бы выделить auckland_number в его собственный шаблон регулярных выражений в PhoneNumberFormats, однако это означает, что он не будет перехватывать новозеландское число в сочетании с ошибками (extra_zero, missing_hyphen, space_instead_of_hyphen).Поэтому, если я не воссоздаю их версию только для Окленда, например, auckland_extra_zero, которая кажется бессмысленно повторяющейся, я не могу понять, как легко это исправить.
  2. Мы не подбираем комбинации ошибок - например, если они имеютдополнительный ноль и пропущенный дефис, мы не будем поднимать это.Есть ли простой способ сделать это с помощью регулярных выражений, без явного создания перестановок различных ошибок?

Я хотел бы решить две вышеупомянутые проблемы и, надеюсь, немного их исправить, чтобы что-то перехватить.что я пропустилЕсть ли более умный способ сделать то, что я пытался сделать выше?

Приветствия, Виктор

Дополнительные комментарии:

Ниже просто приведем некоторый контекст:

Этот сценарий предназначен для глобальной компании с одним офисом в Сиднее, одним в Мельбурне и одним в Окленде.

Цифры взяты из внутреннего списка сотрудников Active Directory (т.е. это не клиентсписок, но наши собственные офисные телефоны).

Следовательно, мы не ищем общий австралийский сценарий сопоставления телефонных номеров, скорее, мы ищем общий сценарий для анализа номеров из трех конкретных офисов.В общем, должны отличаться только последние 4 цифры.

Мобильные телефоны не требуются.

Сценарий предназначен для анализа дампа CSV в Active Directory и переформатирования номеров вприемлемый формат для другой программы (QuickComm)

Эта программа от внешнего поставщика, для которой требуются числа в точном формате, который я создал в приведенном выше коде - поэтому числа выпали, как 0283433422.

Сценарий, который я написал, не может изменить записи, он работает только с их дампом CSV - записи хранятся в Active Directory, и единственный способ получить к ним доступ, чтобы исправить их, - этонапишите сотруднику по электронной почте и попросите его войти в систему и изменить свои собственные записи.

Таким образом, этот скрипт запускается PA, чтобы произвести вывод, требуемый этой программой.Она / он также получит список людей, которые имеют неправильно отформатированные числа - отсюда и сообщения о том, что пользователь просит исправить.Теоретически их должно быть немного.Затем мы отправляем по электронной почте / звоним этим сотрудникам, прося их исправить свои записи - скрипт запускается один раз в месяц (цифры могут меняться), нам также необходимо пометить новых сотрудников, которым также удалось ввести свои записи неправильно.1068 * @ Джон Маклин: Вы рекомендуете ли я удалять регулярные выражения и просто пытаться извлечь цифры конкретной позиции из строки?

Я искал способ отловить типичные случаи ошибок в комбинациях (напримерпробел вместо дефиса в сочетании с дополнительным нулем), но разве это не так просто?

Ответы [ 3 ]

5 голосов
/ 07 июля 2010

Не используйте сложные регулярные выражения.Удалите ВСЕ, кроме цифр - нецифрные ошибки приводят к ошибкам.Если третья цифра равна 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')
>>>

Вам может понравиться(a) завершить некоторые из ваших регулярных выражений \ Z ( NOT $), чтобы они не соответствовали OK, когда есть конечный мусор, или (b) ввести другую группу, чтобы поймать конечный мусор.

и комментарий по социальной инженерии : Вы уже проверяли реакцию пользователя на сотрудника, выполняющего эту директиву: «Пробел вместо дефиса в локальном компоненте - попросите пользователя исправить»?Разве скрипт не может просто исправить и продолжить?

и некоторые комментарии к коду :

self.PHПолный код

(a) ужасно повторяется (если вы должны иметь регулярные выражения, поместите их в список с соответствующими кодами действий и сообщениями об ошибках и выполните итерации по списку)

(b) то же самое для случаев "ошибки", что и для стандартных случаев (так почему вы просите пользователей "исправить" ???)

(c) выбрасывает код страны и заменяет 0, т. е. ваш стандарт +61 (2) 1234-5678 сохраняется как 0212345678 aarrgghhh... даже если у вас есть страна с адресом, который не годится, если NZer мигрирует в Aus и обновляется адрес, но не номер телефона, и, пожалуйста, не говорите, что вы полагаетесь на текущий (нет клиентов NZ за пределамирайон Окленда ???) неперекрытие кодов городов ...

Обновление после раскрытия полной истории

Делайте это ПРОСТО И для вас, и для персонала.Инструкции для сотрудников, использующих Active Directory, должны быть (в зависимости от того, в каком офисе) «Введите +61(2)9876-7, а затем ваш трехзначный добавочный номер».Если они не могут получить это сразу после нескольких попыток, пришло время получить DCM.

Таким образом, вы используете одно регулярное выражение на офис, заполняя постоянную часть, так что офисы SYD имеют номераВ форме +61(2)9876-7ddd вы используете регулярное выражение r"\+61\(2\)9876-7\d{3,3}\Z".Если регулярное выражение соответствует, тогда вы удаляете все не-цифры и используете "0" + the_digits[2:] для следующего приложения.Если нет регулярных выражений, отправьте ракету.

3 голосов
/ 07 июля 2010

+ 1 для рекомендаций @John Machin.

Всемирный справочник телефонных номеров весьма полезен для национальных планов нумерации, особенно для исключений.

ITU также имеет свободно распространяемые стандарты для многих вещей.

0 голосов
/ 07 июля 2010

Телефонные номера отформатированы таким образом, чтобы их было легче запомнить людям - я не вижу причин для их хранения. Почему бы не разделить запятыми и не анализировать каждое число, просто игнорируя все, что не является цифрой?

>>> import string
>>> def parse_number(number):
    n = ''
    for x in number:
        if x in string.digits:
            n += x
    return n

Как только вы это сделаете, вы можете выполнить проверку на основе префикса itl и кода города. (если 3-я цифра 3, тогда должно быть еще 7 цифр и т. д.)

После проверки разделение на компоненты становится простым. Первые две цифры - это префикс, следующая - код города и т. Д. Вы можете проверить все распространенные ошибки, не используя регулярные выражения. Вывод также довольно прост в этом случае.

...