Как правильно прочитать числовые данные из Excel в 1С и убрать разделители разрядов

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

При интеграции 1С с внешними файлами Microsoft Excel разработчики часто сталкиваются с ситуацией, когда числовые данные считываются некорректно. Одной из самых распространенных проблем является наличие визуальных разделителей разрядов (пробелов), из-за которых 1С воспринимает число как строку или вовсе возвращает пустое значение. Разберем детально, почему это происходит и как решить проблему несколькими способами.

Анализ проблемы: почему функция Формат() не помогает

Рассмотрим ситуацию, когда в ячейке Excel число отображается как 37 146,00. Программист пытается считать это значение и применить к нему Формат(ТекущееЗначение, "ЧГ=0"), чтобы убрать группировку, но это не дает результата. Выясним причину: функция Формат() в 1С предназначена для преобразования числа в строку с определенным оформлением. Если же данные из Excel уже пришли в виде строки с пробелами, 1С не опознает в них число, и форматирование не срабатывает. Более того, при попытке присвоить такую строку числовому реквизиту, система может вернуть пустое значение или 0.

Решение 1: Использование свойства .Value вместо .Text

Основная ошибка часто кроется в методе обращения к ячейке Excel через COM-объект. Проанализируем разницу между двумя основными свойствами:

  1. .Text — возвращает строковое представление значения именно в том виде, в котором оно отображается на экране монитора. Если в Excel настроен финансовый формат с пробелами или знаками валют, .Text вернет их все.
  2. .Value — возвращает реальное содержимое ячейки с учетом типа данных. Если в ячейке хранится число, 1С получит именно число (тип Number), независимо от того, как оно раскрашено или отформатировано в самом Excel.

Посмотрим на пример кода, который исправляет ситуацию:


// Неправильно: получаем форматированную строку
ТекущееЗначение = COMОбъект.Cells(НС, 11).Text; 

// Правильно: получаем чистое число
ТекущееЗначение = COMОбъект.Cells(НС, 11).Value;

При использовании .Value разделители групп разрядов исчезают автоматически, так как они являются лишь элементами визуального оформления Excel, а не частью самого числа.

Решение 2: Очистка строки от неразрывных пробелов

Если по какой-то причине вам необходимо считывать данные именно как текст (например, если в колонке могут быть смешанные данные), обычная функция СтрЗаменить(Значение, " ", "") может не сработать. Дело в том, что Excel для разделения разрядов часто использует не стандартный пробел (код 32), а неразрывный пробел (код 160).

Рассмотрим, как правильно очистить строку от таких символов перед преобразованием в число:


// Получаем текстовое значение
ТекстИзЭкселя = COMОбъект.Cells(НС, 11).Text;

// Удаляем обычные пробелы
ТекстИзЭкселя = СтрЗаменить(ТекстИзЭкселя, " ", "");

// Удаляем неразрывные пробелы (Символ 160)
ТекстИзЭкселя = СтрЗаменить(ТекстИзЭкселя, Символ(160), "");

// Заменяем запятую на точку, если это необходимо для функции Число()
// Хотя 1С обычно понимает разделитель текущего сеанса
ТекстИзЭкселя = СтрЗаменить(ТекстИзЭкселя, ",", ".");

// Преобразуем в число
Результат = Число(ТекстИзЭкселя);

Решение 3: Использование свойства .Value2 для повышения стабильности

Для еще более точной работы с данными профессионалы рекомендуют использовать свойство .Value2. Рассмотрим его особенности. В отличие от .Value, свойство .Value2 не проверяет ячейку на соответствие типам "Дата" или "Валюта". Оно возвращает данные в "сыром" виде: даты как числа формата Double, а денежные значения без лишних преобразований. Для 1С это зачастую самый быстрый и стабильный способ получить чистые данные без региональных искажений.


// Самый "чистый" способ получения данных
ТекущееЗначение = COMОбъект.Cells(НС, 11).Value2;

Оптимизация: работа с областями (Range) вместо ячеек

Посмотрим на ситуацию шире. Обращение к каждой ячейке в цикле через Cells(НС, Колонка) — это медленная операция, так как каждый вызов проходит через медленный интерфейс COM. Если в файле тысячи строк, загрузка может занять минуты.

Рассмотрим способ ускорить процесс в десятки раз, прочитав всю область данных целиком в массив 1С:


// Определяем область данных (например, с первой ячейки до конца данных)
ExcelЛист = COMОбъект.Sheets(1);
ВсеДанные = ExcelЛист.UsedRange.Value; // Получаем данные всей таблицы в виде SafeArray

// SafeArray автоматически преобразуется в массив 1С (двумерный)
Для СтрокаМассива = 1 По ВсеДанные.ВГраница(1) Цикл
    // В массиве значения уже будут иметь правильный тип (число, дата или строка)
    ЗначениеКомиссии = ВсеДанные[СтрокаМассива][11];
    // Дальнейшая обработка...
КонецЦикла;

Важные нюансы и очистка памяти

Проанализируем еще один критический момент — зависание процессов EXCEL.EXE в диспетчере задач. Чтобы после работы алгоритма Excel полностью закрывался, необходимо соблюдать строгий порядок уничтожения объектов. Простого закрытия книги недостаточно. Выясним, как это сделать правильно:

  1. Всегда закрывайте книгу методом Close().
  2. Обязательно вызывайте Quit() у главного COM-объекта.
  3. Обнуляйте переменные в обратном порядке: сначала Лист, потом Книга, затем само Приложение.

Пример правильного завершения работы:


// ... код обработки ...
Workbook.Close(Ложь); // Закрываем без сохранения изменений
COMОбъект.Quit();
ExcelЛист = Неопределено;
Workbook = Неопределено;
COMОбъект = Неопределено;

Важное замечание: Если при чтении через .Text вы видите в 1С символы решетки ###, это означает, что колонка в Excel слишком узкая для отображения числа. Это еще один веский довод в пользу использования .Value или .Value2, так как эти свойства возвращают реальное значение независимо от ширины колонки и визуального представления.

← На главную