При разработке интерфейсов на обычных формах (ОФ) в платформе «1С:Предприятие» разработчики часто сталкиваются с крайне странным поведением полей ввода, для которых задана маска. Классический пример — поле ввода номера телефона с маской +7 (999) 999-99-99. Если заполнять это поле интерактивно (руками), всё работает отлично. Но как только мы пытаемся заполнить его программно, платформа начинает вести себя непредсказуемо.
Давайте подробно разберем, почему при программном присвоении номера "9771234567" мы получаем искаженный результат "+7 (971) 234-56-7 ", в то время как номер "9111234567" отображается абсолютно корректно. Мы проанализируем внутренние механизмы платформы, выявим причину бага и рассмотрим три надежных способа обхода этой проблемы.
Когда мы программно присваиваем значение свойству поля ввода на форме (например, в обработчике ПриОткрытии), платформа запускает внутренний парсер сопоставления переданной строки с заданной маской. Этот процесс происходит символ за символом.
В нашей маске +7 (999) 999-99-99 присутствуют символы двух типов:
9, каждая из которых ожидает ввода любой цифры).+, скобки ( ), дефисы -, пробелы и цифра 7 в префиксе).Проанализируем пошагово, как алгоритм платформы обрабатывает строку "9771234567":
+7 (9..) ....+7 (97.) ....1234567) без проблем распределяются по оставшимся спецсимволам маски.+7 (971) 234-56-7 .Почему же номер "9111234567" обрабатывается правильно? Все очень просто. В начале этой строки (на второй и третьей позициях) нет цифры 7. Внутреннему парсеру не за что «зацепиться», ложного совпадения с литералом префикса маски не происходит, и все 10 цифр корректно распределяются по своим местам.
Ниже мы подробно разберем три практических метода решения этой проблемы, чтобы вам не пришлось переписывать архитектуру хранения данных в вашей конфигурации.
---
Самый простой и быстрый способ победить некорректный парсинг — передавать в поле ввода строку, которая уже содержит префикс, совпадающий с литералами маски. Если платформа увидит на входе символы префикса, она сопоставит их со статическим префиксом маски, не затрагивая полезные цифры номера.
Вместо того чтобы напрямую писать:
ПолеВвода1 = "9771234567"; // Приведет к багу
Мы должны дополнить строку префиксом. Достаточно добавить +7 в начало строки, либо полностью привести её к формату маски:
ПолеВвода1 = "+79771234567"; // Отработает корректно
// Или еще более надежный вариант:
ПолеВвода1 = "+7 (977) 123-45-67";
Давайте напишем универсальную вспомогательную функцию, которая будет очищать строку от лишних символов и безопасно приводить любой 10-значный номер к формату, который без ошибок воспримет маска платформы:
Функция ПодготовитьТелефонДляМаски(Знач ВходнойНомер) Экспорт
// Очищаем строку, оставляя только цифры
ЧистыйНомер = "";
Для Позиция = 1 По СтрДлина(ВходнойНомер) Цикл
Символ = Сред(ВходнойНомер, Позиция, 1);
Если Найти("0123456789", Символ) > 0 Тогда
ЧистыйНомер = ЧистыйНомер + Символ;
КонецЕсли;
КонецЦикла;
// Если передан 10-значный номер (например, 9771234567)
Если СтрДлина(ЧистыйНомер) = 10 Тогда
Возврат "+7" + ЧистыйНомер;
// Если номер уже начинается с 7 или 8 и имеет длину 11 символов
ИначеЕсли СтрДлина(ЧистыйНомер) = 11 И (Лев(ЧистыйНомер, 1) = "7" Или Лев(ЧистыйНомер, 1) = "8") Тогда
Возврат "+7" + Сред(ЧистыйНомер, 2);
КонецЕсли;
Возврат ВходнойНомер; // Возвращаем как есть, если формат не распознан
КонецФункции
Теперь в обработчике формы ПриОткрытии достаточно вызвать эту функцию:
Процедура ПриОткрытии()
НомерИзБазы = "9771234567"; // Значение, полученное из реквизита
ЭлементыФормы.ПолеВвода1.Значение = ПодготовитьТелефонДляМаски(НомерИзБазы);
КонецПроцедуры
---
Если вы хотите раз и навсегда исключить влияние подобных багов платформы на логику приложения, рекомендуется отказаться от использования символа 7 в качестве жесткого литерала внутри маски. Мы можем визуально сохранить интерфейс, разделив статическую и динамическую части поля.
Выполним следующие шаги по настройке формы:
+7. Новая маска должна выглядеть так: (999) 999-99-99.+7.При таком подходе в базе данных вы храните чистый 10-значный номер без кода страны (например, "9771234567"). При программном выводе значения на форму платформа больше не будет спотыкаться о префикс, так как в маске (999) 999-99-99 отсутствуют статические цифры. Поведение поля ввода станет стабильным и предсказуемым.
---
Стандартный механизм масок в 1С имеет множество ограничений. Он плохо справляется со вставкой номеров из буфера обмена (копированием/вставкой), жестко привязывает пользователя к одному формату длины номера и часто вызывает раздражение при попытке стереть или отредактировать часть номера.
Проанализируем альтернативный вариант, который часто применяется в современных конфигурациях (в том числе в Библиотеке Стандартных Подсистем — БСП): полный отказ от маски на уровне свойств элемента формы и переход на программное форматирование «на лету».
Для реализации этого метода выполните следующие действия:
ПриИзменении для вашего поля ввода, который будет форматировать текст.Рассмотрим пример программной реализации форматирования ввода пользователя:
Процедура ПолеВвода1ПриИзменении(Элемент)
// Получаем введенный пользователем текст
ВходнойТекст = Элемент.Значение;
// Очищаем от всех символов, кроме цифр
ЧистыйНомер = "";
Для Позиция = 1 По СтрДлина(ВходнойТекст) Цикл
Символ = Сред(ВходнойТекст, Позиция, 1);
Если Найти("0123456789", Символ) > 0 Тогда
ЧистыйНомер = ЧистыйНомер + Символ;
КонецЕсли;
КонецЦикла;
// Форматируем строку под стандартный шаблон телефона
ДлинаНомера = СтрДлина(ЧистыйНомер);
Если ДлинаНомера = 10 Тогда
// Форматируем 9771234567 -> +7 (977) 123-45-67
Элемент.Значение = "+7 (" + Лев(ЧистыйНомер, 3) + ") "
+ Сред(ЧистыйНомер, 4, 3) + "-"
+ Сред(ЧистыйНомер, 7, 2) + "-"
+ Сред(ЧистыйНомер, 9, 2);
ИначеЕсли ДлинаНомера = 11 И (Лев(ЧистыйНомер, 1) = "7" Или Лев(ЧистыйНомер, 1) = "8") Тогда
// Форматируем 89771234567 -> +7 (977) 123-45-67
Элемент.Значение = "+7 (" + Сред(ЧистыйНомер, 2, 3) + ") "
+ Сред(ЧистыйНомер, 5, 3) + "-"
+ Сред(ЧистыйНомер, 8, 2) + "-"
+ Сред(ЧистыйНомер, 10, 2);
КонецЕсли;
КонецПроцедуры
Используя этот подход, мы избавляемся от платформенных багов сопоставления маски, предоставляем пользователю удобный интерфейс для ввода и копирования номеров телефонов в любом формате, а также сохраняем данные в чистоте и порядке.