Как применить форматирование к определенному слову в файле docx, используя Win32 :: Ole в Perl?

Например, мой файл docx содержит следующие предложения:

Это пример Perl
Это пример Python
Это еще один пример Perl

Я хочу применить жирный стиль ко всем вхождениям слова «Perl» следующим образом:

ЭтоPerl пример
Это пример Python
Это другоеPerl пример

Я до сих пор придумал следующий скрипт:

use strict; use warnings;
use Win32::OLE::Const 'Microsoft Word';

my $file = 'E:\test.docx';

my $Word = Win32::OLE->new('Word.Application', 'Quit');
$Word->{'Visible'} = 0;
my $doc = $Word->Documents->Open($file);
my $paragraphs = $doc->Paragraphs() ;
my $enumerate = new Win32::OLE::Enum($paragraphs);


while(defined(my $paragraph = $enumerate->Next())) {

    my $text = $paragraph->{Range}->{Text};
    my $sel = $Word->Selection;
    my $font = $sel->Font;

    if ($text =~ /Perl/){
        $font->{Bold} = 1;              
    }   
    $sel->TypeText($text);          
}

$Word->ActiveDocument->Close ;
$Word->Quit;

Но он применил жирный стиль ко всему абзацу и не редактирует предложения в их первоначальном месте. Это дает мне как модифицированную версию, так и оригинальную версию, как это:

Это пример Perl
Это пример Python
Это еще один пример Perl
Это пример Perl
Это пример Python
Это еще один пример Perl

Как я должен исправить мою проблему. Есть указатели? Спасибо как всегда :)

ОБНОВИТЬ

Задача решена! Большое спасибо@Zaid, а также@cjm :)

Вот код, который прекрасно работает:

while ( defined (my $paragraph = $enumerate->Next()) ) {

    my $words = Win32::OLE::Enum->new( $paragraph->{Range}->{Words} );

    while ( defined ( my $word = $words->Next() ) ) {

        my $font = $word->{Font};
        $font->{Bold} = 1 if $word->{Text} =~ /Perl/;
    }
}

Ответы на вопрос(2)

Решение Вопроса

Попробуйте использоватьWords метод вместоText.

Непроверенные:

while ( defined (my $paragraph = $enumerate->Next()) ) {

    my $words = Win32::OLE::Enum->new( $paragraph->{Range}->{Words} );

    while ( defined ( my $word = $words->Next() ) ) {

        my $font = $word->{Font};
        $font->{Bold} = 1 if $word->{Text} =~ /Perl/;
    }
}
 Mike 23 сент. 2010 г., 11:08
Пример VB на MSDN кажется простым: для каждого aWord в myRange.Words If aWord.Text = "Franklin" Затем aWord.Delete Next aWord. И согласно MSDN, Range.Words возвращает коллекцию слов, которая представляет все слова в диапазоне. Но почему-то это не работает, как ожидалось, используя Win32 :: OLe :( Разочарованный
 Mike 23 сент. 2010 г., 13:49
@ Заид, еще раз спасибо за руководство :) Теперь ближе! Я тестирую ...
 Zaid23 сент. 2010 г., 13:57
$word->{Text} =~ /Perl/возможно?
 Mike 23 сент. 2010 г., 07:55
@ Заид, спасибо за код. Но Perl выдает ошибку «Не ссылка на массив в строке E: \ test.pl 17». Я думаю, что это означает, что $ абзац -> {Range} -> {Words} возвращает хэш-ссылку, а не массив ref.
 Mike 23 сент. 2010 г., 14:02
@ Заид, да! $ word -> {Text} работает прекрасно :) Спасибо за ваше руководство!
 Mike 23 сент. 2010 г., 13:53
Хахаха, @Zaid, мы сделали это! Спасибо :) Я буду обновлять свой пост. Мы все еще не можем напрямую использовать $ word = ~ / Perl /; заявление.
 cjm23 сент. 2010 г., 08:34
@ Майк, попробуйWin32::OLE::Enum->new($paragraph->{Range}->{Words})Так же, как вы делаете для абзацев. (И я рекомендую избегать синтаксиса косвенных объектов; используйтеClass->new вместоnew Class, Когда вы используете косвенный объектный синтаксис, Perl должен угадать, является ли это вызовом метода или обычной функцией, и он может иногда угадывать неправильно.)
 Zaid23 сент. 2010 г., 13:30
@Mike: Глупый я. Причина, почему@words не работает, потому чтоWin32::OLD::Enum->new() возвращаетEnum объект. Ваш$paragraph Пример показывает, как это сделать, поэтому я обновил код соответствующим образом. Имейте в виду, что если это единственное задание, которое вам нужно выполнить,$paragraph Enum на всех. Просто переберите все слова, и все готово.
 Mike 23 сент. 2010 г., 10:58
@Zaid и @cjm, спасибо за руководство. Теперь это кажется ближе. Но массив @words не является набором слов, знаков препинания и т. Д. Я использую оператор print @words, чтобы напечатать его содержимое, и я получаю что-то вроде этого: Win32 :: OLE :: Enum = SCALAR (0x19c2f3c). Таким образом, содержимое @words не является ни хеш-ссылками, ни массивами, и я не могу использовать $ word -> {Font}

Я ничего не знаю о Perl. Но ты смотришь на офис open xml

Вы можете использовать файл .docx как zip-файл и выполнять простой поиск и замену, который работает в миллион раз быстрее, чем взаимодействие. и вам не нужно беспокоиться о миллионах вещей, которые могут пойти не так, как надо.

Переименуйте свой файл .docx в .zip и откройте его, и вы поймете, что я имею в виду.

Ваш ответ на вопрос