Создание регулярных выражений из диапазонов мобильных телефонных номеров

Привет!

Я много работаю с VoIP-сетями. С коммерческим оборудованием, конечно тоже, но и очень много с OpenSource (статья пишется в контексте использования Asterisk PBX).

В телефонии часто возникает простая задача, разделить маршруты на определённые направления. Ну например, направить вызовы на городские номера в сторону оператора 1, МГ — в сторону оператора 2, МН — в сторону оператора 3.
Задача, в общем-то тривиальная, и реализуется на Asterisk легко:

;Местная городская связь: 7 знаков (в разных регионах РФ от 3-х до 7-ми знаков), и номера экстренных служб.
exten => _0X,1,dial(SIP/itsp1/${EXTEN})
exten => _0XX,1,dial(SIP/itsp1/${EXTEN})
exten => _XXXXXXX,1,dial(SIP/itsp1/${EXTEN})
;Междугородняя и мобильная связь: код выхода на МГ связь (в РФ - "8") + 10 знаков.
exten => _8[348]XXXXXXXXX,1,dial(SIP/itsp2/${EXTEN})
exten => _89XXXXXXXXX,1,dial(SIP/itsp2/${EXTEN})
;Международная связь: код выхода на МН связь (в РФ - "810") + номер телефона в международном формате.
exten => _810X.,1,dial(SIP/itsp3/${EXTEN})


Однако иногда возникает необходимость предоставить абоненту доступ только к мобильным телефонам его области, и здесь простым "_89XXXXXXXXX" не отделаешься.

Постановка задачи


Дело в том, что телефонные коды мобильных операторов являются негеографическими (т.н. DEF-коды), а это значит, что привязки кода к конкретному региону нет. Из-за этого в коде «900», например, есть диапазоны, принадлежащие операторам из Вологодской области, Псковской, Чеченской республики, и так далее.
Оператор мобильной связи теоретически может позволить себе выделить любой свободный диапазон в любом регионе, а это приводит к тому, что в разных регионах есть телефонные номера из разных диапазонов с разным количеством номеров. Например, в Вологодской области выделено 46 различных диапазонов, в Московской — 398.

Если бы все диапазоны были «красивыми», по 1000 или 10000 номеров, как например такой: 5100000 — 5109999 (10000 номеров в коде 914), то всё было бы более-менее хорошо.
Но зачастую большие диапазоны по 10000 номеров «разрезаются» на поддиапазоны из чисел, не кратных своему порядку (порядок количества чисел в диапазоне). Навскидку:
Код От До Ёмкость Регион
958 2997500 2998749 1250 Республика Адыгея
958 2998750 2999999 1250 Удмуртская Республика

Или вообще по одному номеру (приводить не буду).
Подобный диапазон (2997500 — 2998749) одним регулярным выражением Asterisk не опишешь, в итоге получится 3 маршрута:
exten => _89582997[5-9]XX,1,dial(SIP/itsp1/${EXTEN})
exten => _89582998[0-6]XX,1,dial(SIP/itsp1/${EXTEN})
exten => _895829987[0-4]X,1,dial(SIP/itsp1/${EXTEN})


И это один конкретный диапазон. Если взять целый регион, то количество регулярных выражений резко увеличивается. В добавок ко всему с течением времени коды DEF имеют свойство меняться. Исчезают одни, появляются другие. Если вы этого не учитываете, это может привести к тому, что ваши абоненты в лучшем случае не смогут звонить на определённые диапазоны вашего региона.

Итак, задача сформулирована: Необходимо из любого количества любых диапазонов создавать регулярные выражения, которые распознает ваша телефонная станция.

Во всех источниках (МТТ, Министерство Связи РФ) фигурируют именно диапазоны, а не регулярные выражения. Так как работа по созданию маршрутов является скучной и рутинной, а мне приходится работать с разными регионами РФ, я решил её автоматизировать. Как ни странно, готовых инструментов я для этого не нашел.
Поэтому инструмент я сделал сам, а заодно и делюсь им со всеми. Эдакий сервис создания регулярных выражений :).

Решение


Возьмём произвольный диапазон (2633722 — 2673388). Человек легко создаст на его основе регулярные выражения. В итоге они получатся такими:
Поддиапазон Регулярное выражение
2633722-2633729 _263372[2-9]
2633730-2633799 _26337[3-9]X
2633800-2633999 _2633[8-9]XX
2634000-2639999 _263[4-9]XXX
2640000-2669999 _26[4-6]XXXX
2670000-2672999 _267[0-2]XXX
2673000-2673299 _2673[0-2]XX
2673300-2673379 _26733[0-7]X
2673380-2673388 _267338[0-8]

Рассмотрим, как это делать автоматически.

Алгоритм

  1. Получить список диапазонов и регионов.
    Я беру диапазоны в удобном табличном виде с сайта ФАС. Реестр обновляется 2 раза в месяц, даже если изменений в нём не было.
  2. Получить список диапазонов того или иного региона (регион вводится пользователем).
    Результатом работы должен быть список регулярных выражений для определённого региона.
  3. Разбить первый диапазон на поддиапазоны, готовые к созданию регулярного выражения.
    Самая сложная часть.
    Я сделал двусвязный список, который изначально содержит 2 элемента (минимум и максимум), и с каждым шагом перед последним элементом добавляется 2 числа: первое число, которое вместе с минимумом способно стать новым диапазоном (если брать пример выше, то на первом шаге это 2633729, на втором — 2633799, и т.д.), и второе число на единицу больше. В каждом шаге рассматриваются предпоследний и последний элементы списка, и между ними вставляются 2 новых элемента. Вполне возможно было обойтись и двумерным массивом, но я изначально посчитал, что мне будет сложнее его наполнять, нежели список.
    В итоге список — это набор пар чисел, каждая из которых способна создать регулярное выражение вида «26337[3-9]X».
  4. Из каждого поддиапазона сделать регулярное выражение.
    Это уже дело техники
  5. Повторить пункты 3 и 4 с каждым диапазоном начального списка.

Реализация и возможности

Я писал на php. В итоге скрипт умеет:
  • Скачивать реестр номеров с сайта ФАС и приводить его к csv в кодировке UTF-8
  • Выдавать пользователю список регулярных выражений, готовых к работе в плане набора Asterisk, для выбранного региона
  • Как бонус принимает на вход любой диапазон натуральных чисел и возвращает список регулярных выражений

Скриншот:
image

Тонкостей при написании возникло много, и вряд ли их стоит здесь перечислять.
Исходный код доступен здесь. В нём много чего можно улучшить (пока в планах суммирование диапазонов перед 3-м пунктом алгоритма и добавление регулярных выражений других форматов, а так же полноценная работа из CLI с целью автоматизации регулярного обновления маршрутов на действующих серверах Asterisk), поэтому прошу писать мне все пожелания. Так же буду рад услышать рекомендации в плане веб-интерфейса и безопасности. Я не программист, поэтому качество кода может страдать.

Ссылки


Поделиться публикацией

Комментарии 24

    0
    А ваш сервис учитывает только коды мобильных операторов? Почему-то для Новосибирской области не показывает код 383 — код стационарных телефонов. В реестре ФАС по данному коду «Слишком большой результат запроса».
      0
      Да, здесь только негеографические, т.е. DEF-коды. Изначально преследовалась цель работать именно с ними.

      ABC-коды не имеют как таковой проблемы «много разных диапазонов в одном регионе», т.к. все ABC-диапазоны принадлежат одному коду региона (в Москве 2 кода). Т.е. в вашем случае вполне работает выражение "_7383XXXXXXX".

      А вообще я собираюсь добавлять функционал работы с ABC, но с другой целью: получение выражений в зависимости не от области, а от конкретного оператора связи в этой области. Смысл — как правило, более короткий и дешёвый путь голосового трафика.
        0
        (в Москве 2 кода)
        А может всё-таки 3 кода (7495,7498,7499) ????
          0
          496 и 498 — это Московская область.
            0
            496 — согласен, без сомнения… а
            498 — уже давно в зоне «Москва»…
              0
              Если обратиться к МТТ или ФАС, то у Москвы нет диапазонов в коде 498. Однако у ФАС нашел забавный момент, в Москве есть диапазоны в третьем коде 478. Про него я не знал, интересно. И МТТ ничего про этот код не знает.
              Скандалы-интриги-расследования
                0
                Ну если, быть точными до конца, есть номера в 7499 и 7495, которые совсем не стационарные, и что?

                МТТ — совсем не авторитет.
                И то, что они по-разному тарифицируют звнок на 7498 и на 7495(7499) — это просто отличнейший повод для судебного разбирательства.
                  0
                  Ну ФАС-то авторитет?) Если верить ФАС, то нет ни одного номера в 7498, закреплённого за Москвой.
                    0
                    Есть Приказ Минсвязи(№ 137 от 30.10.2009 г. — если не ошибаюсь, номер может быть и другим, у меня записан этот в записной ), согласно ему «звонки между географическими кодами 495, 499 и 498 являются местными телефонными соединениями и подлежат оплате как местные вызовы в зависимости от выбранного тарифного плана на местную телефонную связь».

                    И скажем, знаю точно что — ЦентральныйТелеграф и МГТС этот приказ исполняют без всяких вопросов, за остальных операторов — ничего не могу сказать.
      0
      Ваша статья натолкнула меня на решение одной моей задачи, за что вам огромное спасибо :)
      Вы зря считаете себя непрограммистом, код очень понятный и выполняет свою задачу, это главное.
      Использование settype() кстати по-моему говорит, об очень хорошей базе знаний, тут конечно в PHP возможно лучше бы по-другому сделать, но многие другие бы даже просто не задумались в этом месте.
        +1
        Совсем не хочу обидеть автора, но честно говоря, я после пайтоновских re.compile, именованных групп и прочих perl-style фокусов ожидал увидеть нечто большее, чем просто [символьный класс]. Сейчас занимаюсь тоже номерами телефонов на Джанго и вот пример регулярки для валидации формы с телефонным номером ^(?:[78]-?)?(\d{3})[-\.]?(\d{3})[-\.]?(\d{4})$
          0
          Ну вы конечно правы, но ради справедливости. Те кто называют себя «программистами» временами пишут хуже. У автора очень хороший потенциал как у программиста.
            0
            Вот поэтому я и не программист, что не знаю для кого-то очевидных способов улучшить работу программы, так что вы меня вовсе не обижаете :).
            А насчёт регулярок, так в PHP есть perl-совместимость. Но у меня задача обратная стояла, не проверить число на соответствие выражению, а наоборот, создать регулярное выражение. Т.е. та задача, которую обычно делает человек.
            0
            Спасибо, я приятно удивлён :)
            0
            Автор, вы проделали отличную работу! Сам недавно сидел создавал регулярные выражения для мобильных направлений, было бы хорошо если добавили стационарные направления для общей базы! Однозначно в избранное!
              0
              Будет, немного с другой целью (писал выше), но будет.
                0
                Кстати хотелось бы для списка регулярных выражений через тире наименование провайдера!
                  0
                  Запишем в пожелания. Работу с операторами буду делать вместе с добавлением ABC-функционала.
                  0
                  А вообще я мечтаю сделать это для диапазонов всего мира, т.е. не только для регионов РФ. Но где брать официальные источники для каждого города каждой страны — пока плохо представляю, так что эта мечта на последнем месте сейчас.
                • НЛО прилетело и опубликовало эту надпись здесь
                    0
                    Ну в общем-то у меня функция, обрабатывающая подобные диапазоны и формирует префикс, а потом добавляет к нему «X+».
                    А за python спасибо. Интересен этот язык.
                    • НЛО прилетело и опубликовало эту надпись здесь
                  • НЛО прилетело и опубликовало эту надпись здесь
                      0
                      Привет! :)

                    Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                    Самое читаемое