При интеграции с внешними системами, например, при выгрузке данных на сайт партнера, часто возникает задача проверки корректности телефонных номеров. Простая проверка на количество цифр не всегда достаточна, так как внешняя система может требовать не только правильный формат, но и реально существующий код оператора или города. Рассмотрим несколько способов решения этой задачи в 1С, от простых до самых надежных.
Проанализируем ситуацию: необходимо выгружать клиентские данные, но сайт партнера не принимает номера с несуществующими префиксами (например, номер начинающийся с 897...). Наша цель — найти универсальный способ валидации, который позволит отсечь такие номера еще на стороне 1С, до отправки данных.
Самый быстрый способ получить ответ, корректен ли номер, — это воспользоваться готовым внешним сервисом. В обсуждении был предложен вариант использования сайта, который является демонстрацией популярной библиотеки Google Libphonenumber. Этот метод позволяет не только проверить формат, но и получить информацию о типе номера (мобильный, городской), операторе и регионе.
Рассмотрим пример функции на 1С для отправки запроса на такой сервис и получения результата (отлаживать такие запросы удобно через Post1С — аналог Postman на платформе 1С).
Функция ВыполнитьПроверкуНомераТелефона(НомерТелефона)
// Удаляем из номера все символы, кроме цифр
ТолькоЦифры = "";
Для сч = 1 По СтрДлина(НомерТелефона) Цикл
Символ = Сред(НомерТелефона, сч, 1);
Если КодСимвола(Символ) >= 48 И КодСимвола(Символ) <= 57 Тогда
ТолькоЦифры = ТолькоЦифры + Символ;
КонецЕсли;
КонецЦикла;
// Оставляем последние 10 цифр номера (стандарт для РФ)
Если СтрДлина(ТолькоЦифры) > 10 Тогда
НомерДляПроверки = Прав(ТолькоЦифры, 10);
Иначе
НомерДляПроверки = ТолькоЦифры;
КонецЕсли;
АдресСайта = "giggsey.com";
ЗащищенноеСоед = Новый ЗащищенноеСоединениеOpenSSL;
// Указываем порт 443 для HTTPS и таймаут
Соединение = Новый HTTPСоединение(АдресСайта, 443, , , , 30, ЗащищенноеСоед);
// Формируем адрес ресурса с параметрами. Важно: страна RU, язык ru.
// Префикс "7" добавляем к 10-значному номеру.
// Обратите внимание на правильное написание параметра region.
АдресРесурса = "/libphonenumber/index.php?phonenumber=7" + НомерДляПроверки + "&country=RU&language=ru®ion=RU";
Запрос = Новый HTTPЗапрос(АдресРесурса);
Попытка
ОтветHTTP = Соединение.Получить(Запрос);
Исключение
// В случае ошибки сети или таймаута возвращаем описание
Возврат "Ошибка: " + ОписаниеОшибки();
КонецПопытки;
Если ОтветHTTP.КодСостояния = 200 Тогда
// Если запрос успешен, получаем тело ответа
СтрокаОтвета = ОтветHTTP.ПолучитьТелоКакСтроку();
// Парсим полученный HTML для извлечения результата
ЧтениеHTML = Новый ЧтениеHTML;
ЧтениеHTML.УстановитьСтроку(СтрокаОтвета);
Построитель = Новый ПостроительDOM;
ДокHTML = Построитель.Прочитать(ЧтениеHTML);
// Ищем все элементы (ячейки таблицы)
ЭлементыДокHTML = ДокHTML.ПолучитьЭлементыПоИмени("td");
// Эмпирическим путем установлено, что результат валидации находится в 8-й ячейке (индекс 7)
Если ЭлементыДокHTML.Количество() > 7 Тогда
Ответ = СокрЛП(ЭлементыДокHTML.Элемент(7).ТекстовоеСодержимое);
Возврат (Ответ = "true"); // Возвращаем Булево: Истина, если номер валиден
Иначе
Возврат "Ошибка: не удалось разобрать ответ сервера";
КонецЕсли;
Иначе
// Если код состояния не 200, возвращаем ошибку
Возврат "Ошибка HTTP: " + ОтветHTTP.КодСостояния;
КонецЕсли;
КонецФункции
Важные моменты этого подхода:
- Зависимость. Ваша система будет полностью зависеть от доступности и работоспособности стороннего сайта. Если он "упадет" или изменит структуру HTML-страницы, функция перестанет работать.
- Безопасность. Вы передаете телефонные номера клиентов, которые являются персональными данными, на сторонний ресурс. Это может быть нарушением политики безопасности вашей компании.
- Производительность. При массовой проверке большого количества номеров каждый запрос будет занимать время, что замедлит общую обработку.
Этот метод хорошо подходит для разовых проверок или как временное решение, но для стабильной работы в продакшене лучше рассмотреть другие варианты.
Решение 2: Проверка формата с помощью регулярных выражений
Начиная с платформы 1С:Предприятие 8.3.23, появился мощный инструмент для работы со строками — регулярные выражения. Они позволяют проверить, соответствует ли строка определенному шаблону. Этот способ идеален для проверки формата номера.
Для этого используется функция СтрПодобнаПоРегулярномуВыражению(). Рассмотрим пример, который проверяет российские номера телефонов в различных форматах написания (для проверки шаблонов используйте тестирование регулярных выражений на 1С).
ПроверяемыйНомер = "+7 (916) 123-45-67";
// Регулярное выражение для проверки российских номеров
// ^((8|\+7)[\- ]?)? — начало строки, может быть 8 или +7, за которыми может быть пробел или дефис. Знак ? означает, что эта группа не обязательна.
// (\(?\d{3}\)?[\- ]?)? — далее может идти код оператора из 3 цифр, возможно в скобках, и с пробелом/дефисом после.
// [\d\- ]{7,10}$ — в конце должно быть от 7 до 10 символов, состоящих из цифр, дефисов или пробелов.
Шаблон = "^((8|\+7)[\- ]?)?(\(?\d{3}\)?[\- ]?)?[\d\- ]{7,10}$";
Если Не СтрПодобнаПоРегулярномуВыражению(ПроверяемыйНомер, Шаблон, Истина) Тогда
ВызватьИсключение "Пожалуйста, заполните корректный номер телефона. Пример: +7 999 1234567";
КонецЕсли;
Преимущества:
- Скорость и автономность. Проверка выполняется мгновенно средствами самой платформы 1С и не требует доступа в интернет.
- Гибкость. Можно составить очень сложные шаблоны для проверки разных форматов.
Главный недостаток:
Регулярные выражения проверяют только синтаксис (формат), но не семантику (смысл). То есть номер `+7 (999) 111-22-33` пройдет проверку формата, даже если код `999` не выделен ни одному оператору. Таким образом, этот метод не решает исходную задачу отсева номеров с несуществующими кодами.
Решение 3: Локальная проверка по официальным реестрам (наиболее надежный способ)
Чтобы проверять не только формат, но и реальность существования номерной емкости, необходимо сверяться с авторитетным источником. В России таким источником является Минцифры (ранее Россвязь), которое публикует реестры Российской системы и плана нумерации.
Эти данные находятся в открытом доступе и делятся на два основных типа:
- Реестр DEF-кодов: "негеографические" коды (900-999), которые используются мобильными операторами.
- Реестр ABC-кодов: "географические" коды городов и регионов.
Данные публикуются в формате CSV. Идея заключается в том, чтобы загрузить эти данные в 1С и выполнять проверку локально.
Разберем по шагам, как это реализовать:
-
Загрузка реестров.
Найдите на официальном сайте Минцифры или на портале открытых данных (`opendata.digital.gov.ru`) и скачайте актуальные CSV-файлы с реестрами. Если при попытке скачать данные из 1С с помощью HTTPСоединение возникает ошибка 301 (постоянный редирект), попробуйте в заголовках HTTP-запроса указать User-Agent, имитирующий браузер, или убедитесь, что ваше ЗащищенноеСоединениеOpenSSL настроено для работы с российскими сертификатами. Проще всего скачать файлы вручную и добавить их в макеты конфигурации.
-
Создание структуры для хранения.
В конфигурации создайте регистр сведений, например, ДиапазоныТелефонныхНомеров.
- Измерения:
КодОператора (Число, 3), НачалоДиапазона (Число, 7), КонецДиапазона (Число, 7).
- Ресурсы:
ОператорСвязи (Строка), Регион (Строка).
-
Заполнение регистра.
Напишите обработку, которая будет читать данные из CSV-файлов и заполнять созданный регистр сведений. Каждая строка в файле-реестре обычно содержит код (например, 916), начальный номер диапазона (например, 1230000), конечный номер (например, 1239999), наименование оператора и регион.
-
Создание функции проверки.
Теперь можно написать финальную функцию, которая будет использовать эти данные.
Функция ПроверитьРеальностьНомераРФ(НомерТелефона)
// 1. Нормализация номера
НомерБезСимволов = "";
Для сч = 1 По СтрДлина(НомерТелефона) Цикл
Символ = Сред(НомерТелефона, сч, 1);
Если КодСимвола(Символ) >= 48 И КодСимвола(Символ) <= 57 Тогда
НомерБезСимволов = НомерБезСимволов + Символ;
КонецЕсли;
КонецЦикла;
// Приводим к стандарту 10 цифр (без 7 или 8)
Если СтрДлина(НомерБезСимволов) = 11 И (Начало(НомерБезСимволов, 1) = "7" Или Начало(НомерБезСимволов, 1) = "8") Тогда
НормализованныйНомер = Сред(НомерБезСимволов, 2);
ИначеЕсли СтрДлина(НомерБезСимволов) = 10 Тогда
НормализованныйНомер = НомерБезСимволов;
Иначе
Возврат Ложь; // Неверная длина номера
КонецЕсли;
// 2. Выделение кода и номера абонента
КодОператора = Число(Лев(НормализованныйНомер, 3));
НомерАбонента = Число(Прав(НормализованныйНомер, 7));
// 3. Поиск в регистре сведений
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ ПЕРВЫЕ 1
| ИСТИНА КАК Результат
|ИЗ
| РегистрСведений.ДиапазоныТелефонныхНомеров КАК ДиапазоныТелефонныхНомеров
|ГДЕ
| ДиапазоныТелефонныхНомеров.КодОператора = &КодОператора
| И &НомерАбонента МЕЖДУ ДиапазоныТелефонныхНомеров.НачалоДиапазона И ДиапазоныТелефонныхНомеров.КонецДиапазона";
Запрос.УстановитьПараметр("КодОператора", КодОператора);
Запрос.УстановитьПараметр("НомерАбонента", НомерАбонента);
РезультатЗапроса = Запрос.Выполнить();
Возврат Не РезультатЗапроса.Пустой();
КонецФункции
Преимущества этого метода:
- Максимальная надежность: Проверка основана на официальных данных.
- Полная автономность: После первоначальной загрузки данных система не зависит от внешних ресурсов.
- Высокая производительность: Запрос к регистру сведений выполняется очень быстро.
- Безопасность: Персональные данные клиентов не покидают вашу информационную систему.
Необходимо лишь периодически (например, раз в квартал) обновлять данные в регистре, скачивая свежие версии реестров.
Вывод
Выбор способа проверки телефонного номера зависит от ваших требований. Для простой проверки формата на форме ввода отлично подойдут регулярные выражения. Если нужна быстрая, но не самая надежная проверка "здесь и сейчас", можно использовать внешний API. Однако для построения стабильной и безопасной бизнес-логики, особенно при интеграции с партнерами, наиболее правильным и профессиональным решением является создание локальной базы кодов на основе официальных реестров и проверка номеров по ней.