При автоматизации документооборота часто возникает задача не просто создать новый файл Word, а обновить данные в уже существующем шаблоне. Например, при повторной выгрузке справочника в документ необходимо удалить старые записи и вставить актуальные. В этой статье мы разберем несколько подходов к решению этой задачи: от полной очистки документа до точечного удаления фрагментов между текстовыми маркерами или с использованием механизмов закладок.
Для начала рассмотрим типичный код инициализации COM-объекта Word, который часто используют разработчики. Проанализируем пример, предоставленный в обсуждении, и разберем, как он работает:
// Создание объекта и открытие файла
WordПриложение = Новый COMОбъект("Word.Application");
WordПриложение.Visible = Истина;
WordПриложение.Documents.Open(ПутьКФайлу);
WordФайл = WordПриложение.ActiveDocument;
// Вставка текста через Selection
WordПриложение.Selection.TypeText("БД- " + Справочники.Организации.НаименованиеПоУмолчанию);
WordПриложение.Selection.TypeText(Символ(10));
В данном примере используется объект Selection. Это аналог курсора, который видит пользователь. Основная проблема этого метода заключается в том, что текст просто добавляется в текущую позицию курсора. Если мы запустим этот код повторно, новые данные просто «приклеятся» к старым. Выясним, как этого избежать.
Если логика вашей задачи подразумевает, что при каждой выгрузке документ должен заполняться «с нуля», самым простым и надежным решением будет полная очистка всего содержимого файла перед началом цикла заполнения. Рассмотрим, как это реализовать одной командой:
// Очищаем все содержимое активного документа
WordФайл.Range().Delete();
После выполнения этой команды объект Range, охватывающий весь документ, вызывает метод Delete. Курсор автоматически устанавливается в начало пустого документа, и вы можете приступать к записи новых данных. Это исключает дублирование информации и гарантирует актуальность выгрузки.
Рассмотрим более сложную ситуацию, когда в документе Word есть статический текст (шапка, подписи), который нельзя удалять, и динамическая область, ограниченная текстовыми метками, например, «Начало БД № 1» и «Конец БД № 1». Нам нужно программно найти всё, что находится между ними, и удалить. Разберем алгоритм по шагам:
Range) между этими точками.Посмотрим на пример реализации такого поиска:
Поиск = WordПриложение.Selection.Find;
Поиск.ClearFormatting();
Поиск.Text = "Начало БД № 1";
Если Поиск.Execute() Тогда
НачалоДиапазона = WordПриложение.Selection.Start;
// Ищем конец блока
Поиск.Text = "Конец БД № 1";
Если Поиск.Execute() Тогда
КонецДиапазона = WordПриложение.Selection.End;
// Создаем объект Range и удаляем содержимое
УдаляемыйОбласть = WordФайл.Range(НачалоДиапазона, КонецДиапазона);
УдаляемыйОбласть.Delete();
КонецЕсли;
КонецЕсли;
Важный нюанс: использование текстовых маркеров небезопасно, так как пользователь может случайно изменить или удалить одну букву в маркере, и поиск перестанет работать. Проанализируем более профессиональный подход.
Наиболее надежный способ управления областями текста в Word — это использование механизма Закладок. Вы можете заранее создать в шаблоне Word закладку (через меню «Вставка — Закладка») и дать ей имя, например, ДанныеВыгрузки. В коде 1С мы будем обращаться к этой области напрямую по имени.
Рассмотрим преимущества и пример кода:
ИмяЗакладки = "ДанныеВыгрузки";
Если WordФайл.Bookmarks.Exists(ИмяЗакладки) Тогда
// Получаем диапазон закладки
ОбластьЗакладки = WordФайл.Bookmarks.Item(ИмяЗакладки).Range;
// Очищаем старый текст
ОбластьЗакладки.Text = "";
// Вставляем новые данные в эту же область
ОбластьЗакладки.InsertAfter("Новая информация из 1С...");
// Если нужно сохранить закладку для будущих выгрузок,
// ее необходимо пересоздать, так как при замене текста она может удалиться
WordФайл.Bookmarks.Add(ИмяЗакладки, ОбластьЗакладки);
КонецЕсли;
Как справедливо заметили участники обсуждения, часто проблема «лишних» данных в документе решается еще на этапе их подготовки в 1С. Вместо того чтобы построчно выводить данные и проверять их в Word, лучше сначала подготовить «чистый» набор данных с помощью запроса или ТаблицыЗначений.
Разберем, как подготовить уникальные записи без дублей, чтобы не пришлось ничего удалять в самом Word:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| ДополнительныеОтчетыИОбработки.ИмяОбъекта КАК ИмяОбъекта,
| ДополнительныеОтчетыИОбработки.Версия КАК Версия
|ИЗ
| Справочник.ДополнительныеОтчетыИОбработки КАК ДополнительныеОтчетыИОбработки";
РезультатЗапроса = Запрос.Выполнить();
ТЗ_Данные = РезультатЗапроса.Выгрузить();
// Теперь выгружаем в Word уже готовую таблицу
Для Каждого СтрокаТЗ Из ТЗ_Данные Цикл
ТекстДляВставки = СтрШаблон("%1 (версия %2)", СтрокаТЗ.ИмяОбъекта, СтрокаТЗ.Версия);
WordПриложение.Selection.TypeText(ТекстДляВставки + Символы.ПС);
КонецЦикла;
Использование функции СтрШаблон позволяет формировать строку один раз в памяти 1С и передавать ее в COM-объект, что работает значительно быстрее, чем множественные вызовы TypeText для каждого поля.
Проанализируем несколько технических моментов, которые помогут сделать вашу обработку быстрее и стабильнее:
WordПриложение.ScreenUpdating = Ложь;. Это ускорит процесс выгрузки в несколько раз, так как Word не будет перерисовывать документ при каждой вставке символа.Range работает в фоновом режиме и не требует перемещения видимого курсора, что снижает нагрузку на систему.WordПриложение.Quit(); и обнуляйте переменную WordПриложение = Неопределено;, иначе в диспетчере задач будут скапливаться «зависшие» процессы Word.Символы.ПС или Символ(13) (возврат каретки), так как Символ(10) (перевод строки) может интерпретироваться в Word как мягкий перенос.Выяснив все технические детали, мы можем сделать вывод: для разового обновления всего документа лучше использовать полную очистку через Range().Delete(), а для сложной замены фрагментов текста в шаблонах — механизм закладок (Bookmarks). Подготовка данных в 1С с помощью запросов с ключевым словом РАЗЛИЧНЫЕ позволит избежать появления дубликатов, которые автор темы изначально хотел удалять вручную.