Привет!
Я много работаю с 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] |
Рассмотрим, как это делать автоматически.
Алгоритм
- Получить список диапазонов и регионов.
Я беру диапазоны в удобном табличном виде с сайта ФАС. Реестр обновляется 2 раза в месяц, даже если изменений в нём не было. - Получить список диапазонов того или иного региона (регион вводится пользователем).
Результатом работы должен быть список регулярных выражений для определённого региона. - Разбить первый диапазон на поддиапазоны, готовые к созданию регулярного выражения.
Самая сложная часть.
Я сделал двусвязный список, который изначально содержит 2 элемента (минимум и максимум), и с каждым шагом перед последним элементом добавляется 2 числа: первое число, которое вместе с минимумом способно стать новым диапазоном (если брать пример выше, то на первом шаге это 2633729, на втором — 2633799, и т.д.), и второе число на единицу больше. В каждом шаге рассматриваются предпоследний и последний элементы списка, и между ними вставляются 2 новых элемента. Вполне возможно было обойтись и двумерным массивом, но я изначально посчитал, что мне будет сложнее его наполнять, нежели список.
В итоге список — это набор пар чисел, каждая из которых способна создать регулярное выражение вида «26337[3-9]X». - Из каждого поддиапазона сделать регулярное выражение.
Это уже дело техники - Повторить пункты 3 и 4 с каждым диапазоном начального списка.
Реализация и возможности
Я писал на php. В итоге скрипт умеет:
- Скачивать реестр номеров с сайта ФАС и приводить его к csv в кодировке UTF-8
- Выдавать пользователю список регулярных выражений, готовых к работе в плане набора Asterisk, для выбранного региона
- Как бонус принимает на вход любой диапазон натуральных чисел и возвращает список регулярных выражений
Скриншот:
Тонкостей при написании возникло много, и вряд ли их стоит здесь перечислять.
Исходный код доступен здесь. В нём много чего можно улучшить (пока в планах суммирование диапазонов перед 3-м пунктом алгоритма и добавление регулярных выражений других форматов, а так же полноценная работа из CLI с целью автоматизации регулярного обновления маршрутов на действующих серверах Asterisk), поэтому прошу писать мне все пожелания. Так же буду рад услышать рекомендации в плане веб-интерфейса и безопасности. Я не программист, поэтому качество кода может страдать.
Ссылки
- Скрипт в действии: http://rootblog.ru/regex/
Все имена регионов взяты из реестра на сайте ФАС и не изменялись. - Реестр ФАС: www.rossvyaz.ru/activity/num_resurs/registerNum/
- Для сравнения диапазоны на сайте МТТ: http://www.mtt.ru/mtt/def
- Телефонный план нумерации России в Википедии
Автор: sasharu