Pull to refresh

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

Reading time 4 min
Views 15K
Привет!

Я много работаю с 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), поэтому прошу писать мне все пожелания. Так же буду рад услышать рекомендации в плане веб-интерфейса и безопасности. Я не программист, поэтому качество кода может страдать.

Ссылки


Tags:
Hubs:
+18
Comments 24
Comments Comments 24

Articles