При автоматизации загрузки данных из внешних файлов в 1С:УПП или другие конфигурации разработчики часто сталкиваются с ситуацией, когда стандартные методы чтения возвращают «сырое» числовое значение, игнорируя единицы измерения (например, «грн.», «евро» или «шт.»), заданные через формат ячейки. Особенно это актуально в окружениях, где запрещена установка Microsoft Excel и используется альтернативный пакет LibreOffice или OpenOffice.
В этой статье мы подробно разберем, как изменить алгоритм чтения, чтобы получать не только значения, но и отображаемый текст с учетом форматирования, а также научимся анализировать маски форматов для определения типа данных.
Разберем ситуацию: в ячейке Excel записано число 100, но благодаря денежному формату пользователь видит 100 грн.. При использовании метода getDataArray(), который часто применяется для ускорения загрузки, 1С получает массив чистых значений типа Double. Система LibreOffice Calc разделяет внутреннее содержимое ячейки и её визуальное представление. Для решения задачи нам необходимо обратиться к объектам, которые отвечают за рендеринг текста.
Самый простой способ получить значение вместе с «грн.» или «евро» — это обращение к свойству String каждой конкретной ячейки. В отличие от Value, это свойство возвращает строку именно в том виде, в котором она отображается в интерфейсе Calc.
Проанализируем, как изменить исходный код для построчного обхода:
// Вместо пакетного получения данных через Range.getDataArray()
// используем поочередное обращение к ячейкам
Для НомерСтроки = begRow По endRow Цикл
НовСтрока = локТабЗнач.Добавить();
Для НомерКолонки = begCol По endCol Цикл
// Получаем объект конкретной ячейки
ТекущаяЯчейка = Sheet.getCellByPosition(НомерКолонки, НомерСтроки);
// Читаем именно строковое представление (с валютой, знаками и т.д.)
ОтображаемыйТекст = ТекущаяЯчейка.getString();
НовСтрока[НомерКолонки] = ОтображаемыйТекст;
КонецЦикла;
КонецЦикла;
Важно: Обращение к каждой ячейке через COM-соединение работает медленнее, чем получение всего массива данных сразу. Однако это единственный надежный способ «увидеть» текст так, как его видит пользователь.
Если нам нужно не просто получить строку, а программно понять, что это именно валюта (чтобы, например, разделить число 100 и валюту грн. в разные колонки), мы должны проанализировать идентификатор формата ячейки. Каждая ячейка в LibreOffice имеет свойство NumberFormat.
Рассмотрим алгоритм получения маски формата:
Document.getNumberFormats().NumberFormat (это целочисленный индекс).getByKey() выгрузим структуру формата и проанализируем свойство FormatStr.Пример кода для реализации этой логики:
// Получаем доступ к библиотеке форматов документа
ВсеФорматы = Document.getNumberFormats();
ТекущаяЯчейка = Sheet.getCellByPosition(0, 10); // Пример для конкретной ячейки
ИндексФормата = ТекущаяЯчейка.NumberFormat;
// Извлекаем настройки формата по индексу
СтруктураФормата = ВсеФорматы.getByKey(ИндексФормата);
МаскаФормата = СтруктураФормата.FormatStr;
// Теперь мы можем проверить, содержится ли в маске обозначение валюты
Если Найти(МаскаФормата, "грн") > 0 Тогда
Сообщить("Это денежный формат в гривнах");
ИначеЕсли Найти(МаскаФормата, "€") > 0 Тогда
Сообщить("Это денежный формат в евро");
КонецЕсли;
Этот метод позволяет сохранить точность вычислений (работать с числом), при этом точно зная, какая валюта была указана в исходном файле.
Выясним важную техническую деталь: начиная с версии платформы 8.3.6, компания 1С добавила возможность нативного чтения файлов .xls и .xlsx на уровне платформы. Это работает даже на Linux-серверах и не требует установленного офисного пакета. Этот метод часто является самым стабильным и быстрым.
Рассмотрим, как это реализовать через объект ТабличныйДокумент:
ТабДок = Новый ТабличныйДокумент;
Попытка
ТабДок.Прочитать(ПутьКФайлу);
Исключение
Сообщить("Не удалось прочитать файл: " + ОписаниеОшибки());
Возврат;
КонецПопытки;
// Теперь обходим ячейки таблицы 1С
Для НомерСтроки = 1 По ТабДок.ВысотаТаблицы Цикл
Для НомерКолонки = 1 По ТабДок.ШиринаТаблицы Цикл
// Свойство .Текст вернет отображаемое значение (например, "100 грн.")
ЗначениеСВалютой = ТабДок.Область(НомерСтроки, НомерКолонки).Текст;
// Свойство .Значение вернет только число (например, 100)
ЧистоеЧисло = ТабДок.Область(НомерСтроки, НомерКолонки).СодержитЗначение;
// Выполняем логику обработки данных...
КонецЦикла;
КонецЦикла;
Использование ТабличныйДокумент позволяет избежать проблем с правами доступа к COM-объектам на сервере и значительно упрощает поддержку кода, так как вы перестаете зависеть от версии установленного LibreOffice.
Выбор метода зависит от ваших конкретных условий:
ТекущаяЯчейка.getString().NumberFormat и FormatStr через объект NumberFormats.ТабличныйДокумент.Прочитать().Помните, что при работе с форматом .xls (старый бинарный формат) могут возникать специфические ошибки интерпретации спецсимволов, поэтому всегда проверяйте результат загрузки на тестовых данных с различными валютными знаками.