1С 8.3 Конвертация из Word в табличный документ - Программист 1С Минск. Автоматизация бизнеса.

Перейти к контенту

1С 8.3 Конвертация из Word в табличный документ

Данные > Примеры кода 1С > 1С 8.3 Табличный документ / Макет
Перейти в основной раздел:
Механизм использует СОМ, в режиме чтения вытаскивая из документа самое основное. Получающийся табличный документ единый по разметке ширин областей, т.е. без сюрпризов (хотя, может, наоборот надо бы каждый абзац в свой формат). Рассчитано на А4 и документ из одной "колонки", это наиболее частые случаи в практике. Умеет абзацы с минимумом форматирования, простые и нумерованные списки, таблицы.
// by Якoв_Кoгaн
Основная функция
Функция ВывестиДокументВордВМоксель(ИмяФайла)

   Попытка
       // Для пересчётов использовать вхВорд.CentimetersToPoints(ЧислоСМ) и вхВорд.PointsToCentimeters(ЧислоПунктов)
       вСантиметр=6.25; // в средних символах шрифта
       //(при необходимости пересчитывать по вДиапазон.CharacterWidth - ширина символов, константа WdCharacterWidth

       вШиринаСтраницы=75; // эмпирически, довести до ума с учётом
       //сообщить("стран ширина "+стран.PageWidth+", высота "+стран.PageHeight); // в пунктах, работает

       // Типовые настройки документа Ворд:
       // 1.25 до номера (отступ первой строки) и 1.89 табуляция (до основного текста)
       // Размеры листа А4 в сантиметрах: 21х29.7

       вхВорд=Новый COMОбъект("Word.Application");
       вПодтверждатьПреобразования=Истина;
       вТолькоЧтение=Истина;
       вДокумент=вхВорд.Documents.Open(ИмяФайла, вПодтверждатьПреобразования, вТолькоЧтение);

        #Область Проверки
       вСтраница=вДокумент.PageSetup;
       Если вСтраница.TextColumns.Count>1 Тогда
           Сообщить("Текущая версия не обрабатывает многоколонные документы!");
           вДокумент.Close(Ложь); // без сохранения
           вхВорд.Quit(0);
           вхВорд="";
           Возврат Неопределено;
       КонецЕсли;
       вШиринаСтраницыВорда=Окр(вхВорд.PointsToCentimeters(вСтраница.PageWidth),2);
       вВысотаСтраницыВорда=Окр(вхВорд.PointsToCentimeters(вСтраница.PageHeight),2);
       Если НЕ ((20<=вШиринаСтраницыВорда И вШиринаСтраницыВорда<=22) И
           (28<=вВысотаСтраницыВорда И вВысотаСтраницыВорда<=30)) Тогда
           Сообщить("Текущая версия не обрабатывает размеры страницы, отличающиеся от А4!");
           вДокумент.Close(Ложь); // без сохранения
           вхВорд.Quit(0);
           вхВорд="";
           Возврат Неопределено;
       КонецЕсли;
        #КонецОбласти

       // подготовка вывода таблиц
       мКомТаблиц=Новый Массив;
       Для Каждого вхТаблица Из вДокумент.Tables Цикл
           мКомТаблиц.Добавить(Новый Структура("Начало,Конец,Таблица",вхТаблица.Range.Start,вхТаблица.Range.End,вхТаблица));
       КонецЦикла;

        #Область ПодготовкаВыводаНумерованныхСписков
       // можно, конечно, рСписок.ConvertNumbersToText(ТипНомера)
       //- но это не лучший выход, и это изменение документа

       СоотПараграфовСписков=Новый Соответствие;
       // свойство вДокумент.Lists.Count ситуационно-зависимое, не применять!
       Для Каждого рСписок Из вДокумент.Lists Цикл
           //ОбработкаПрерыванияПользователя();
           // рЛист.CountNumberedItems();
           Для Каждого вПараграфСписка Из рСписок.ListParagraphs Цикл
               //ОбработкаПрерыванияПользователя();
               рФорматСписка=вПараграфСписка.Range.ListFormat;
               рТипСписка=рФорматСписка.ListType; // WdListType
               Если рТипСписка=0 Или рТипСписка=2 Или рТипСписка=6 Тогда
                   // ненумерованные и bullet игнорируем
               Иначе
                   // заниматься иерархией с проверкой погружения (рФорматСписка.ListLevelNumber) не будем,
                   // нам достаточно проверить так:
                   вПредставлениеПункта=СокрЛП(рФорматСписка.ListString);
                   // выравнивание смотрим по первой позиции уровней (хотя можно перебирать,
                   // смотреть по позиции или по NumberFormat)
                   Попытка вВыравнивание=рФорматСписка.ListTemplate.ListLevels.Item(0).Alignment
                   Исключение вВыравнивание=0 КонецПопытки;
                   // из первого уровня также можно брать NumberPosition - отступ,если будет надо;
                   //он в пунктах, поэтому тоже может потребоваться пересчёт!
                   Если СтрРазделить(вПредставлениеПункта,".",Ложь).Найти(рФорматСписка.ListValue)=0 Тогда
                       Сообщить("Внимание! Нарушение нумерации списка для "+вПредставлениеПункта+"!");
                   КонецЕсли;
                   // фиксируем для дальнейшего вывода
                   СоотПараграфовСписков.Вставить(вПараграфСписка.Range.Start,
                   Новый Структура("Номер,Выравнивание", вПредставлениеПункта, вВыравнивание));
               КонецЕсли;
           КонецЦикла;
       КонецЦикла;
        #КонецОбласти

       // FitTextWidth для диапазонов НЕ используем, в т.ч. для вДокумент.Range()

       тд=Новый ТабличныйДокумент;

        #Область ПодготовкаТабДокумента
       // устанавливаем ширины рабочих колонок А4
       вСтолбец=1;
       Пока Истина Цикл
           тд.Область(1,вСтолбец,1,вСтолбец).ШиринаКолонки=Окр(вСантиметр/4,2);
           вСтолбец=вСтолбец+1;
           Если тд.ШиринаТаблицы>вШиринаСтраницы Тогда
               Прервать;
           КонецЕсли;
       КонецЦикла;
        #КонецОбласти

        #Область ВыводОсновныхДанных
       вСтрока=1;
       вПравыйКрайнийСтолбец=тд.ШиринаТаблицы;
       вИдетТаблица=Ложь;

       Для Каждого вПараграф Из вДокумент.Paragraphs Цикл
           //ОбработкаПрерыванияПользователя();
           // к сожалению, вПараграф.ListNumberOriginal использовать ненадёнжно
           вДиапазон=вПараграф.Range;
           вТекстДиапазона=вДиапазон.Text;
           вНачалоДиапазона=вДиапазон.Start;
           вКонецДиапазона=вДиапазон.End;

            #Область ВыводПозицииНумерованногоСписка
           // использовать вДиапазон.ListFormat.ListLevelNumber и
           // вДиапазон.ListFormat.ListValue не рекомендуется
           вПараграфСписка=СоотПараграфовСписков.Получить(вНачалоДиапазона);
           Если вПараграфСписка=Неопределено Тогда
               вПредставлениеПункта="";
               вВыравнивание=0;
           Иначе
               вПредставлениеПункта=СокрЛП(вПараграфСписка.Номер);
               вВыравнивание=вПараграфСписка.Выравнивание;
           КонецЕсли;
           Если ПустаяСтрока(вПредставлениеПункта) Тогда
               // нумерации списка нет
               вГраницаОбластиПараграфа=1;
           Иначе // надо выводить № пункта списка
               вОбластьНомера=тд.Область(вСтрока,1,вСтрока,4);
               вОбластьНомера.Объединить();
               вОбластьНомера.Текст=вПредставлениеПункта;
               // или вДиапазон.ListStyle.Font, если они разные:
               вОбластьНомера.Шрифт=ПостроительШрифта(вДиапазон.Font);
               вОбластьНомера.ГоризонтальноеПоложение=ПолучениеВыравнивания(вВыравнивание);
               вОбластьНомера.ВертикальноеПоложение=ВертикальноеПоложение.Верх; // по умолчанию
               вГраницаОбластиПараграфа=5;
           КонецЕсли;
            #КонецОбласти

           вхТаблица=Неопределено;
           Для Каждого знч Из мКомТаблиц Цикл
               Если знч.Начало<=вНачалоДиапазона И вНачалоДиапазона<=знч.Конец
                   И знч.Начало<=вКонецДиапазона И вКонецДиапазона<=знч.Конец
                   Тогда // можно было бы вДиапазон.InRange(вхТаблица.Range), но оно медленнее
                   вхТаблица=знч.Таблица; Прервать;
               КонецЕсли;
           КонецЦикла;

           Если вхТаблица=Неопределено Тогда
               вИдетТаблица=Ложь;

                #Область ВыводОбычногоАбзаца
               // для параграфа и Диапазон.ParagraphFormat, при необходимости:
               // вПараграф.FirstLineIndent - Возвращает или устанавливает значение
               // в пунктах для первой линии или отступа.

               // вПараграф.LeftIndent - Отступ слева в пунктах.
               // вПараграф.RightIndent - Отступ справа в пунктах.
               // вПараграф.LineSpacing - Междустрочный интервал.

               // вПараграф.PageSetup.PageWidth аналогично ширине документа в целом,
               // можно не заморачиваться

               вОбластьПараграфа=тд.Область(вСтрока,вГраницаОбластиПараграфа,вСтрока,вПравыйКрайнийСтолбец);
               вОбластьПараграфа.Объединить();
               вОбластьПараграфа.Текст=вТекстДиапазона;
               вОбластьПараграфа.Шрифт=ПостроительШрифта(вДиапазон.Font); // а не вПараграф.Style.Font!
               // или лучше вДиапазон.ParagraphFormat.Alignment?:
               вОбластьПараграфа.ГоризонтальноеПоложение=ПолучениеВыравнивания(вПараграф.Alignment);
               вОбластьПараграфа.ВертикальноеПоложение=ВертикальноеПоложение.Верх; // по умолчанию
               вОбластьПараграфа.РазмещениеТекста=ТипРазмещенияТекстаТабличногоДокумента.Переносить; // по умолчанию
                #КонецОбласти

               вСтрока=вСтрока+1;
           Иначе
               Если не вИдетТаблица Тогда // выводим таблицу,
                   // а далее пропускаем все входящие в неё диапазоны, и идём до её конца
                   ВывестиТаблицу(вхВорд, вхТаблица, тд, вСтрока);
               КонецЕсли;
               вИдетТаблица=Истина;
               Продолжить; // вСтрока уже "промотана" до нужной позиции пост-таблицы
           КонецЕсли;

       КонецЦикла;

        #КонецОбласти

       вДокумент.Close(Ложь); // без сохранения
       вхВорд.Quit(0);
       вхВорд="";

       Возврат тд;

   Исключение

       Сообщить("Ошибка: "+ОписаниеОшибки());
       Возврат Неопределено;

   КонецПопытки;

КонецФункции
Функция ПостроительШрифта(вхШрифт)

   Возврат Новый Шрифт(вхШрифт.Name, вхШрифт.Size,    вхШрифт.Bold,
   вхШрифт.Italic, вхШрифт.Underline, вхШрифт.StrikeThrough, вхШрифт.Scaling);

КонецФункции
Функция ПостроительРамкиЯчейки(вхРамка, вхОтступ)

   Если вхРамка.Visible Тогда
       чисСтиль=вхРамка.LineStyle;
       вТолщина=1;
       Если чисСтиль=1 Тогда
           вТипЛинии=ТипЛинииЯчейкиТабличногоДокумента.Сплошная;
           // если надо, толщину можно сделать подробнее по вхРамка.LineWidth
       ИначеЕсли чисСтиль=2 Тогда
           вТипЛинии=ТипЛинииЯчейкиТабличногоДокумента.Точечная;
       ИначеЕсли чисСтиль=5 Тогда
           вТипЛинии=ТипЛинииЯчейкиТабличногоДокумента.РедкийПунктир;
       ИначеЕсли чисСтиль=6 Тогда
           вТипЛинии=ТипЛинииЯчейкиТабличногоДокумента.ЧастыйПунктир;
       ИначеЕсли чисСтиль=7 Тогда
           вТипЛинии=ТипЛинииЯчейкиТабличногоДокумента.Двойная;
       Иначе
           вТипЛинии=ТипЛинииЯчейкиТабличногоДокумента.БольшойПунктир;
       КонецЕсли;
       вОтступ=(вхОтступ>0);
       Возврат Новый Линия(вТипЛинии, вТолщина, вОтступ);
   Иначе
       Возврат Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.НетЛинии);
   КонецЕсли;

КонецФункции
Функция ПолучениеВыравнивания(Выравн)

   // wdListLevelAlignCenter - 1 – По центру wdListLevelAlignLeft -
   // 0 – По левому краю wdListLevelAlignRight - 2 – По правому краю
   Если Выравн=1 Тогда
       Возврат ГоризонтальноеПоложение.Центр;
   ИначеЕсли Выравн=2 Тогда
       Возврат ГоризонтальноеПоложение.Право;
   ИначеЕсли Выравн=3 Тогда
       Возврат ГоризонтальноеПоложение.ПоШирине;
   Иначе
       Возврат ГоризонтальноеПоложение.Лево;
   КонецЕсли;

КонецФункции
Процедура ВывестиТаблицу(вхВорд, вхТаблица, табДокумент, текСтр)

   вСантиметр=6.25;
   вСимвол7=Символ(7);

   колСтр=вхТаблица.Rows.Count;
   колКолонок=вхТаблица.Columns.Count;

   Для вСтрокаДок=1 По колСтр Цикл
       вСтолбец=1;

       Для вСтолбецДок=1 По колКолонок Цикл
           Попытка
               вЯчейка=вхТаблица.Cell(вСтрокаДок,вСтолбецДок);
           Исключение
               Продолжить;
           КонецПопытки;

           колЯчеекМхл=Окр(вхВорд.PointsToCentimeters(вЯчейка.Width*4),0,РежимОкругления.Окр15как20); // 1 см. это 4 ячейки мхл
           вОбластьЯчейки=табДокумент.Область(текСтр,вСтолбец,текСтр,вСтолбец+колЯчеекМхл-1);
           вОбластьЯчейки.Объединить();

           Если вЯчейка.FitText Или вЯчейка.WordWrap Тогда // пока так
               вОбластьЯчейки.РазмещениеТекста=ТипРазмещенияТекстаТабличногоДокумента.Переносить;
           Иначе
               вОбластьЯчейки.РазмещениеТекста=ТипРазмещенияТекстаТабличногоДокумента.Авто;
           КонецЕсли;

           вДиапазонЯчейки=вЯчейка.Range;
           //
           вТекстДиапазонаЯчейки=СокрЛП(вДиапазонЯчейки.Text);
           Если Прав(вТекстДиапазонаЯчейки,1)=вСимвол7 Тогда
               вТекстДиапазонаЯчейки=Лев(вТекстДиапазонаЯчейки,СтрДлина(вТекстДиапазонаЯчейки)-1);
           КонецЕсли;
           вОбластьЯчейки.Текст=вТекстДиапазонаЯчейки;
           //
           вОбластьЯчейки.Шрифт=ПостроительШрифта(вДиапазонЯчейки.Font);

           // на практике удобнее оставлять автовысоту, но иногда может понадобиться:
           //вОбластьЯчейки.АвтоВысотаСтроки=Ложь;
           //вОбластьЯчейки.ВысотаСтроки=вСантиметр*Окр(вхВорд.PointsToCentimeters(вЯчейка.Height),0,РежимОкругления.Окр15как20);

           вОбластьЯчейки.ГоризонтальноеПоложение=ПолучениеВыравнивания(вДиапазонЯчейки.ParagraphFormat.Alignment);
           // отступ - в пунктах, при необходимости требуется пересчёт!
           //Если вОбластьЯчейки.ГоризонтальноеПоложение=ГоризонтальноеПоложение.Лево Тогда
           //    вОбластьЯчейки.Отступ=вЯчейка.LeftPadding;
           //ИначеЕсли вОбластьЯчейки.ГоризонтальноеПоложение=ГоризонтальноеПоложение.Право Тогда
           //    вОбластьЯчейки.Отступ=вЯчейка.RightPadding;
           //КонецЕсли;

           вертВыравнивание=вЯчейка.VerticalAlignment;
           Если вертВыравнивание=1 Тогда
               вОбластьЯчейки.ВертикальноеПоложение=ВертикальноеПоложение.Центр;
           ИначеЕсли вертВыравнивание=3 Тогда
               вОбластьЯчейки.ВертикальноеПоложение=ВертикальноеПоложение.Низ;
           Иначе
               вОбластьЯчейки.ВертикальноеПоложение=ВертикальноеПоложение.Верх;
           КонецЕсли;

           вОбластьЯчейки.ГраницаСверху=ПостроительРамкиЯчейки(вЯчейка.Borders(-1),вЯчейка.Borders.DistanceFromTop);
           вОбластьЯчейки.ГраницаСлева=ПостроительРамкиЯчейки(вЯчейка.Borders(-2),вЯчейка.Borders.DistanceFromLeft);
           вОбластьЯчейки.ГраницаСнизу=ПостроительРамкиЯчейки(вЯчейка.Borders(-3),вЯчейка.Borders.DistanceFromBottom);
           вОбластьЯчейки.ГраницаСправа=ПостроительРамкиЯчейки(вЯчейка.Borders(-4),вЯчейка.Borders.DistanceFromRight);

           вСтолбец=вСтолбец+колЯчеекМхл;
       КонецЦикла;

       текСтр=текСтр+1;
   КонецЦикла;

КонецПроцедуры
0
комментарии
____________________
Copyright©, «Программист 1С в г.Минске», 21.08.2021
Перепечатка текста и фотографий разрешена при наличии прямой ссылки на источник
Яндекс.Метрика
Защищенное соединение ssl
visa
mastercard
Maestro
Яндекс деньги
Назад к содержимому