【问题标题】:How do I apply formatting to a particular word in a docx file using Win32::Ole in Perl?如何在 Perl 中使用 Win32::Ole 将格式应用于 docx 文件中的特定单词?
【发布时间】:2011-04-16 01:04:43
【问题描述】:

例如,我的 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/;
    }
}

【问题讨论】:

    标签: perl formatting win32ole


    【解决方案1】:

    我对 perl 一无所知。 但是你看office open xml

    您可以将 .docx 文件视为 zip 文件,然后进行简单的搜索和替换,这比互操作快一百万倍。而且您也不必担心可能会出错的数百万件事情。

    将你的 .docx 文件重命名为 .zip 并打开它,你就会明白我的意思了。

    【讨论】:

      【解决方案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/;
          }
      }
      

      【讨论】:

      • @Zaid,感谢您的代码。但是 perl 向我抛出错误“不是 E:\test.pl 第 17 行的数组引用”。我认为这意味着 $paragraph->{Range}->{Words} 返回一个 hashref,而不是一个数组 ref。
      • @Mike,试试Win32::OLE::Enum->new($paragraph->{Range}->{Words}),就像你对段落所做的那样。 (而且我建议避免使用间接对象语法;使用Class->new 而不是new Class。当您使用间接对象语法时,Perl 必须猜测它是方法调用还是普通函数,它偶尔会猜错。)
      • @Zaid 和 @cjm,感谢您的指导。现在这似乎更接近了。但是@words 数组不是单词、标点符号等的集合。我使用 print @words 语句来打印它的内容,我收到类似这样的信息:Win32::OLE::Enum=SCALAR(0x19c2f3c)。所以@words 的内容既不是哈希引用也不是数组引用,我不能使用 $word->{Font}
      • MSDN 上的 VB 示例看起来很简单: For Each aWord In myRange.Words If aWord.Text = "Franklin " Then aWord.Delete Next aWord。根据 MSDN,Range.Words 返回一个 Words 集合,表示范围内的所有单词。但不知何故,它不能按预期使用 Win32::OLe :( Frustrated
      • @Mike:我傻了。 @words 不起作用的原因是 Win32::OLD::Enum->new() 返回一个 Enum 对象。您的 $paragraph 示例显示了如何执行此操作,因此我相应地更新了代码。请记住,如果这是您需要执行的唯一任务,则根本不需要 $paragraph 枚举。只需遍历所有单词即可。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多