При разработке механизмов импорта данных из внешних файлов, таких как Excel, программисты 1С часто сталкиваются с ситуацией, когда данные до 1000 загружаются корректно, а числа, начиная с 1000 и выше, вызывают ошибку «Преобразование значения к типу Число не может быть выполнено». Это происходит из-за особенностей форматирования ячеек в Excel и того, как 1С интерпретирует текстовое представление этих данных.
В этой статье мы подробно разберем причины возникновения этой ошибки, проанализируем разницу между визуальным представлением данных и их внутренним содержанием, а также составим универсальный алгоритм для безопасного преобразования «грязных» строк в числовой формат 1С.
Давайте проанализируем ситуацию. Когда мы используем метод ТекущаяОбласть.Текст при чтении ТабличногоДокумента, 1С получает строку в точности так, как она отображается на экране. Excel для удобства пользователя часто добавляет в числа разделители разрядов. Для чисел больше 999 таким разделителем обычно выступает неразрывный пробел.
Важный нюанс: обычный пробел (код символа 32) и неразрывный пробел (код символа 160) — это разные символы для системы. Стандартная функция 1С Число() ожидает на вход строку, состоящую исключительно из цифр и одного десятичного разделителя (запятой или точки, в зависимости от настроек). Любой лишний символ, будь то пробел, неразрывный пробел или символ валюты, приводит к аварийному завершению операции.
Прежде чем приступать к очистке строки, давайте рассмотрим, как мы получаем данные. Часто в коде встречается следующий подход:
Кол = ТабДок.ПолучитьОбласть("R" + Формат(НомерСтроки, "ЧГ=0") + "C3").ТекущаяОбласть.Текст;
Проблема здесь заключается в использовании свойства Текст. Если наша задача — получить числовое значение, более правильным будет проверить, содержит ли область значение, и обратиться напрямую к нему. Давайте посмотрим, как изменить логику получения данных:
ОбластьЯчейки = ТабДок.Область(НомерСтроки, 3);
Если ОбластьЯчейки.СодержитЗначение Тогда
ЗначениеКоличества = ОбластьЯчейки.Значение;
Иначе
ЗначениеКоличества = ОбластьЯчейки.Текст;
КонецЕсли;
Если ячейка в Excel была отформатирована как числовая, 1С при чтении файла методом Прочитать() может автоматически распознать тип и вернуть уже готовое число. В этом случае дополнительные преобразования не потребуются.
Если же мы вынуждены работать с текстовым представлением (например, формат ячейки в Excel был «Текстовый»), нам необходимо гарантированно удалить все разделители разрядов. Как мы выяснили, основной виновник — неразрывный пробел. Рассмотрим, как эффективно его удалить.
В языке 1С существует встроенная константа Символы.НПП, которая соответствует неразрывному пробелу. Проанализируем пример кода для очистки:
// Удаляем неразрывные пробелы
ТекКол = СтрЗаменить(Кол, Символы.НПП, "");
// На всякий случай удаляем обычные пробелы
ТекКол = СтрЗаменить(ТекКол, " ", "");
Иногда разработчики используют Символ(160), что идентично Символы.НПП. Однако использование предопределенной константы делает код более читаемым и понятным.
Следующая проблема — различие в десятичных разделителях. В зависимости от региональных настроек Windows, разделителем может быть как точка, так и запятая. В Excel часто встречается формат, где разделителем тысяч является запятая, а десятичным разделителем — точка (американский стандарт).
Выясним, как сделать преобразование универсальным. Мы рекомендуем приводить все разделители к запятой (или к точке, в зависимости от того, что понимает ваш сеанс 1С), предварительно удалив разделители тысяч. Посмотрим на программную реализацию:
// Предположим, что запятая — это разделитель тысяч, а точка — десятичный разделитель
// Сначала удаляем запятые (разделители тысяч)
ЧистаяСтрока = СтрЗаменить(ТекКол, ",", "");
// Затем заменяем точку на запятую для корректной работы функции Число() в русской локализации
ЧистаяСтрока = СтрЗаменить(ЧистаяСтрока, ".", ",");
Попытка
РезультатЧисло = Число(ЧистаяСтрока);
Исключение
Сообщить("Не удалось преобразовать значение: " + ТекКол);
РезультатЧисло = 0;
КонецПопытки;
Чтобы не дублировать код для каждой колонки (Количество, Цена, Сумма), целесообразно вынести логику в отдельную функцию. Это позволит нам централизованно обрабатывать все возможные «грязные» символы, которые могут прийти из Excel.
Рассмотрим пример такой функции:
Функция ПреобразоватьСтрокуВЧисло(Знач ВходнаяСтрока) Экспорт
// Если передано уже число, просто возвращаем его
Если ТипЗнч(ВходнаяСтрока) = Тип("Число") Тогда
Возврат ВходнаяСтрока;
КонецЕсли;
// Удаляем все виды пробелов
Результат = СтрЗаменить(ВходнаяСтрока, Символы.НПП, "");
Результат = СтрЗаменить(Результат, " ", "");
// Удаляем возможные кавычки (часто встречаются в CSV или при копировании)
Результат = СтрЗаменить(Результат, """", "");
// Обрабатываем десятичные знаки.
// Если в строке есть и точка, и запятая, значит запятая — разделитель тысяч (1,250.50)
Если СтрНайти(Результат, ",") > 0 И СтрНайти(Результат, ".") > 0 Тогда
Результат = СтрЗаменить(Результат, ",", ""); // Удаляем разделитель тысяч
КонецЕсли;
// Приводим точку к запятой (для стандартной работы Число() в РФ)
Результат = СтрЗаменить(Результат, ".", ",");
Попытка
Возврат Число(Результат);
Исключение
Возврат 0;
КонецПопытки;
КонецФункции
Разберем еще несколько важных моментов, которые помогут избежать ошибок при загрузке данных:
Число() выдаст ошибку. Используйте ПустаяСтрока().ТаблицуЗначений, убедитесь, что колонка имеет тип ОписаниеТипов("Число", Новый КвалификаторыЧисла(15, 3)). Это предотвратит ошибки при дальнейшей записи в документ.КодСимвола(Стр, Позиция). Проверьте каждый символ в проблемной строке. Если вы видите код 160 — это неразрывный пробел, если код 8239 — это узкий неразрывный пробел, который также нужно удалять.СокрЛП(), чтобы удалить случайные пробелы в начале и в конце считанной строки.Проанализировав ситуацию с загрузкой 1000 и более единиц товара, мы видим, что проблема всегда кроется в визуальном форматировании. Применяя вышеописанные методы очистки строк, мы обеспечим стабильную работу нашей обработки загрузки вне зависимости от того, как настроен Excel у пользователя.