При интеграции 1С с электронными таблицами Microsoft Excel разработчики нередко сталкиваются с ситуацией, когда текстовые поля переносятся корректно, а числовые значения (цены, количества, суммы) считываются с ошибками: дробная часть отсекается, числа становятся неожиданно маленькими либо вовсе превращаются в ноль. Разберем детально, почему это происходит при работе через COM-объект, проанализируем типичные ошибки в исходном коде и рассмотрим правильные варианты загрузки данных.
Рассмотрим типовой фрагмент кода, который часто приводит к ошибкам при загрузке:
Excel = Новый COMОбъект("Excel.Application");
Excel.Workbooks.Open("c:\nomen.xls");
Книга = Excel.ActiveWorkbook;
строкадокумента.Цена = СокрЛП((Excel.Cells(Строка, 3).Value));
В этой конструкции кроется сразу несколько критических уязвимостей, приводящих к порче числовых данных:
СокрЛП: функция СокрЛП ожидает на входе строку и возвращает строку. Когда числовое значение из свойства Value оборачивается в СокрЛП, а затем присваивается числовой колонке строкадокумента.Цена, платформа 1С выполняет обратное неявное преобразование строки в число. Если в операционной системе разделителем разрядов выступает пробел, а десятичным разделителем является запятая, 1С преобразует строку только до первого недопустимого символа. В результате строка вида "1 250" превращается в 1.Символы.НПП), который стандартная функция СокрЛП не удаляет.Value в COM-модели Excel: свойство Value преобразует финансовые форматы в COM-тип Currency, который округляет значение до четырех знаков после запятой и зависит от региональных настроек Windows.Excel.Cells(...) обращается к текущему активному листу глобального приложения. Если при открытии файла активным оказался другой лист или пользователь переключил окно, считывание произойдет из непредвиденной ячейки.Если ячейка в Excel действительно содержит числовой формат, то свойство ячейки уже возвращает значение числового типа. Применение функций СокрЛП к числу избыточно и вредно. Посмотрим на корректный вариант считывания:
Лист = Книга.Sheets(1);
строкадокумента.Цена = Лист.Cells(Строка, 3).Value;
Чтобы избежать искажения вещественных чисел и валютных форматов, на уровне COM-объекта Excel рекомендуется использовать свойство Value2 вместо Value. Свойство Value2 возвращает значение базового типа Double без применения регионального форматирования валют:
строкадокумента.Цена = Лист.Cells(Строка, 3).Value2;
В некоторых файлах числа хранятся как отформатированный текст либо считываются через свойство Text (которое возвращает именно видимое отображение числа в ячейке). В этом случае перед преобразованием строки в число необходимо обязательно удалить все невидимые разделители групп разрядов, включая неразрывный пробел, и привести десятичный разделитель к системному стандарту.
Разберем по шагам, как обработать такую строку:
Лист = Книга.Sheets(1);
СтроковоеЗначение = Лист.Cells(Строка, 3).Text;
// Удаляем обычные пробелы и неразрывные пробелы (Символы.НПП)
СтроковоеЗначение = СтрЗаменить(СтроковоеЗначение, Символы.НПП, "");
СтроковоеЗначение = СтрЗаменить(СтроковоеЗначение, " ", "");
// Приводим точку к запятой, если в региональных настройках 1С разделителем является запятая
СтроковоеЗначение = СтрЗаменить(СтроковоеЗначение, ".", ",");
// Безопасно преобразуем очищенную строку в число
Попытка
строкадокумента.Цена = Число(СтроковоеЗначение);
Исключение
строкадокумента.Цена = 0;
КонецПопытки;
Использование COM-объекта Excel.Application имеет существенные недостатки: требуется установленный MS Office на рабочей станции или сервере, возникают конфликты разрядности (32 и 64 бит), а поячеечное чтение выполняется крайне медленно. Платформа 1С:Предприятие позволяет читать файлы Excel напрямую с помощью объекта ТабличныйДокумент.
Рассмотрим, как прочитать файл и получить точные числовые значения без искажений:
ТабДок = Новый ТабличныйДокумент;
ТабДок.Прочитать("c:\nomen.xls");
Для НомерСтроки = 1 По ТабДок.ВысотаТаблицы Цикл
ОбластьЯчейки = ТабДок.Область(НомерСтроки, 3);
Если ОбластьЯчейки.СодержитЗначение Тогда
// Свойство Значение содержит исходное число без строковых разделителей
строкадокумента.Цена = ОбластьЯчейки.Значение;
Иначе
// Если значение прочитано как текст, выполняем очистку
СтрЧисла = СтрЗаменить(ОбластьЯчейки.Текст, Символы.НПП, "");
СтрЧисла = СтрЗаменить(СтрЧисла, " ", "");
СтрЧисла = СтрЗаменить(СтрЧисла, ".", ",");
строкадокумента.Цена = Число(СтрЧисла);
КонецЕсли;
КонецЦикла;
Использование ТабличныйДокумент гарантирует правильное распознавание встроенных типов данных ячеек и полностью исключает зависимость от установленных в операционной системе офисных пакетов.