При интеграции 1С с внешними файлами Microsoft Excel разработчики часто сталкиваются с ситуацией, когда числовые данные считываются некорректно. Одной из самых распространенных проблем является наличие визуальных разделителей разрядов (пробелов), из-за которых 1С воспринимает число как строку или вовсе возвращает пустое значение. Разберем детально, почему это происходит и как решить проблему несколькими способами.
Рассмотрим ситуацию, когда в ячейке Excel число отображается как 37 146,00. Программист пытается считать это значение и применить к нему Формат(ТекущееЗначение, "ЧГ=0"), чтобы убрать группировку, но это не дает результата. Выясним причину: функция Формат() в 1С предназначена для преобразования числа в строку с определенным оформлением. Если же данные из Excel уже пришли в виде строки с пробелами, 1С не опознает в них число, и форматирование не срабатывает. Более того, при попытке присвоить такую строку числовому реквизиту, система может вернуть пустое значение или 0.
Основная ошибка часто кроется в методе обращения к ячейке Excel через COM-объект. Проанализируем разницу между двумя основными свойствами:
.Text вернет их все.Number), независимо от того, как оно раскрашено или отформатировано в самом Excel.Посмотрим на пример кода, который исправляет ситуацию:
// Неправильно: получаем форматированную строку
ТекущееЗначение = COMОбъект.Cells(НС, 11).Text;
// Правильно: получаем чистое число
ТекущееЗначение = COMОбъект.Cells(НС, 11).Value;
При использовании .Value разделители групп разрядов исчезают автоматически, так как они являются лишь элементами визуального оформления Excel, а не частью самого числа.
Если по какой-то причине вам необходимо считывать данные именно как текст (например, если в колонке могут быть смешанные данные), обычная функция СтрЗаменить(Значение, " ", "") может не сработать. Дело в том, что Excel для разделения разрядов часто использует не стандартный пробел (код 32), а неразрывный пробел (код 160).
Рассмотрим, как правильно очистить строку от таких символов перед преобразованием в число:
// Получаем текстовое значение
ТекстИзЭкселя = COMОбъект.Cells(НС, 11).Text;
// Удаляем обычные пробелы
ТекстИзЭкселя = СтрЗаменить(ТекстИзЭкселя, " ", "");
// Удаляем неразрывные пробелы (Символ 160)
ТекстИзЭкселя = СтрЗаменить(ТекстИзЭкселя, Символ(160), "");
// Заменяем запятую на точку, если это необходимо для функции Число()
// Хотя 1С обычно понимает разделитель текущего сеанса
ТекстИзЭкселя = СтрЗаменить(ТекстИзЭкселя, ",", ".");
// Преобразуем в число
Результат = Число(ТекстИзЭкселя);
Для еще более точной работы с данными профессионалы рекомендуют использовать свойство .Value2. Рассмотрим его особенности. В отличие от .Value, свойство .Value2 не проверяет ячейку на соответствие типам "Дата" или "Валюта". Оно возвращает данные в "сыром" виде: даты как числа формата Double, а денежные значения без лишних преобразований. Для 1С это зачастую самый быстрый и стабильный способ получить чистые данные без региональных искажений.
// Самый "чистый" способ получения данных
ТекущееЗначение = COMОбъект.Cells(НС, 11).Value2;
Посмотрим на ситуацию шире. Обращение к каждой ячейке в цикле через Cells(НС, Колонка) — это медленная операция, так как каждый вызов проходит через медленный интерфейс COM. Если в файле тысячи строк, загрузка может занять минуты.
Рассмотрим способ ускорить процесс в десятки раз, прочитав всю область данных целиком в массив 1С:
// Определяем область данных (например, с первой ячейки до конца данных)
ExcelЛист = COMОбъект.Sheets(1);
ВсеДанные = ExcelЛист.UsedRange.Value; // Получаем данные всей таблицы в виде SafeArray
// SafeArray автоматически преобразуется в массив 1С (двумерный)
Для СтрокаМассива = 1 По ВсеДанные.ВГраница(1) Цикл
// В массиве значения уже будут иметь правильный тип (число, дата или строка)
ЗначениеКомиссии = ВсеДанные[СтрокаМассива][11];
// Дальнейшая обработка...
КонецЦикла;
Проанализируем еще один критический момент — зависание процессов EXCEL.EXE в диспетчере задач. Чтобы после работы алгоритма Excel полностью закрывался, необходимо соблюдать строгий порядок уничтожения объектов. Простого закрытия книги недостаточно. Выясним, как это сделать правильно:
Close().Quit() у главного COM-объекта.Пример правильного завершения работы:
// ... код обработки ...
Workbook.Close(Ложь); // Закрываем без сохранения изменений
COMОбъект.Quit();
ExcelЛист = Неопределено;
Workbook = Неопределено;
COMОбъект = Неопределено;
Важное замечание: Если при чтении через .Text вы видите в 1С символы решетки ###, это означает, что колонка в Excel слишком узкая для отображения числа. Это еще один веский довод в пользу использования .Value или .Value2, так как эти свойства возвращают реальное значение независимо от ширины колонки и визуального представления.