Разработка под мобильную платформу «1С:Предприятие» имеет множество нюансов, связанных с тем, что мобильные операционные системы (Android и iOS) накладывают свои ограничения и используют собственные системные библиотеки локализации. Часто разработчики сталкиваются с ситуацией, когда код, идеально работающий на настольной («большой») платформе, на мобильном устройстве начинает вести себя непредсказуемо.
В этой статье мы подробно разберем один крайне коварный баг мобильной платформы, связанный с неявным преобразованием дробных чисел в строку, выясним причины его возникновения и рассмотрим эффективные методы решения этой проблемы.
Представим стандартную ситуацию: в коде выполняется вывод дробного числа на экран или его неявное преобразование в строку. Например, мы пишем простейшую конструкцию:
Сообщить(Число(1.234));
На настольной платформе мы получим ожидаемый результат (например, "1,234" в зависимости от локали). Однако на некоторых версиях мобильной платформы (в частности, на ветках 8.3.10.х) на экране появится строка "1 234". Точка или запятая, отделяющая дробную часть, загадочным образом превращается в пробел!
При этом наблюдается странная закономерность:
Число(1.234) преобразуется в "1 234" (с пробелом).Число(1.2345) преобразуется корректно: "1,2345" (с запятой).Число(1.2340), платформа выведет нормальное число "1,234".Давайте разберем по шагам, почему так происходит, чем это грозит разработчику и как исправить поведение платформы.
Поведение системы объясняется особенностями работы парсера и форматтера чисел в мобильной платформе 1С, которые тесно завязаны на региональные настройки операционной системы устройства.
В русской локали приняты следующие стандарты форматирования чисел:
При вызове функции Сообщить() происходит неявное приведение переданного значения к типу Строка. В старых версиях мобильного движка алгоритм форматирования содержал ошибку: когда на вход поступало число ровно с тремя знаками в дробной части, парсер ошибочно распознавал эту тройку цифр как полноценную «триаду» (тысячную группу) целой части числа. В результате вместо разделения дробной части платформа применяла правила группировки разрядов целой части и заменяла разделитель на пробел.
Если количество знаков после запятой отличалось от трех (было меньше или больше), шаблон группы из трех цифр не совпадал, алгоритм отрабатывал штатно, и разделитель оставался на месте.
Многие разработчики, обнаружив пробел в строке числа, пытаются решить проблему «в лоб» с помощью стандартной функции удаления пробелов:
Результат = СтрЗаменить(СтрокаЧисла, " ", "");
Проанализируем эту ситуацию. На самом деле такой код не сработает. Дело в том, что платформа вставляет в качестве разделителя не обычный пробел (символ с ASCII-кодом 32), а неразрывный пробел (символ Символы.НПП, Unicode-код 160 или U+00A0).
Чтобы удалить такой символ вручную, необходимо использовать системные константы 1С:
// Правильное удаление неразрывного пробела
Результат = СтрЗаменить(СтрокаЧисла, Символы.НПП, "");
// Или альтернативный вариант через код символа
Результат = СтрЗаменить(СтрокаЧисла, Символ(160), "");
Данная ошибка критична не только из-за эстетического отображения чисел на экране пользователя. Гораздо серьезнее последствия при обмене данными.
Если в мобильном приложении настроена отправка данных на веб-сервер, в базу SQL или интеграция со сторонними сервисами через форматы XML, JSON или CSV, неявное преобразование типов может полностью заблокировать обмен:
"1 234" вместо стандартного double-формата "1.234".Рассмотрим три надежных способа обойти и полностью решить эту проблему на мобильной платформе.
Самый надежный способ, гарантирующий стабильную работу кода на любой платформе (как мобильной, так и настольной) независимо от региональных настроек устройства — это полное исключение неявного преобразования типов. Никогда не полагайтесь на автоматическое приведение числа к строке!
Для гарантированного получения строки без лишних символов группировки используйте встроенную функцию Формат() с параметром ЧГ=0 (отключение группировки разрядов):
// Исключаем группировку разрядов (пробелы исчезнут)
СтрокаДляВыгрузки = Формат(МоеЧисло, "ЧГ=0");
Если вам необходимо подготовить число для передачи во внешние API (где в качестве разделителя дробной части жестко требуется точка), используйте явную установку разделителя дробной части ЧРД=.:
// Отключаем группировку и жестко задаем точку в качестве разделителя
СтрокаДляAPI = Формат(МоеЧисло, "ЧГ=0; ЧРД=.");
Сообщить(СтрокаДляAPI); // Выведет "1.234" при любых региональных настройках
Если вы хотите переопределить стандартное поведение форматирования для всей конфигурации целиком, выполните следующие действия в Конфигураторе:
Важное примечание: На некоторых старых релизах мобильной платформы системные настройки операционной системы Android/iOS могут иметь более высокий приоритет, чем региональные установки конфигурации 1С. Поэтому использование явного форматирования через Формат() в коде остается более приоритетным и безопасным вариантом.
Поскольку данная проблема локализации является явным багом платформы, разработчики фирмы «1С» зафиксировали её и исправили в последующих релизах.
Если в вашей системе до сих пор используется устаревшая ветка платформы (например, 8.3.10.84), мы настоятельно рекомендуем выполнить обновление мобильной платформы до актуальных версий (начиная с линеек 8.3.11, 8.3.12 и выше). В новых версиях логика форматирования чисел приведена в полное соответствие с настольной платформой, и ошибка с ошибочной группировкой трех знаков дробной части полностью устранена.