【问题标题】:Finding and Replacing with VBA for Word overwrites previous style用 VBA for Word 查找和替换会覆盖以前的样式
【发布时间】:2019-11-06 16:24:30
【问题描述】:

我正在编写一个 VBA 脚本来从已定义的模板生成 word 文档。在其中,我需要能够编写标题以及每个标题的正文。作为一个小例子,我有一个只包含<PLACEHOLDER> 的word 文档。对于我需要编写的每个标题和正文,我使用 VBA 中的查找和替换功能来查找 <PLACEHOLDER> 并将其替换为标题名称、换行符,然后再次替换为 <PLACEHOLDER>。重复此操作,直到写入每个标题名称和正文,然后将最后的 <PLACEHOLDER> 替换为换行符。

文本替换工作正常,但我指定的样式会被替换的 next 调用覆盖。这导致我刚刚替换的所有内容都具有我对替换函数的 last 调用的样式。

VBA 代码(运行main

Option Explicit

Sub replace_stuff(search_string As String, replace_string As String, style As Integer)
    With ActiveDocument.Range.Find
        .Text = search_string
        .Replacement.Text = replace_string
        .Replacement.style = style
        .Forward = True
        .Wrap = wdFindContinue
        .Format = True
        .MatchWholeWord = False
        .MatchSoundsLike = False
        .MatchAllWordForms = False
        .Execute Replace:=wdReplaceAll
    End With
End Sub

Sub main()
    Dim section_names(2) As String
    section_names(0) = "Introduction"
    section_names(1) = "Background"
    section_names(2) = "Conclusion"

    Dim section_bodies(2) As String
    section_bodies(0) = "This is the body text for the introduction! Fetched from some file."
    section_bodies(1) = "And Background... I have no issue fetching data from the files."
    section_bodies(2) = "And for the conclusion... But I want the styles to 'stick'!"

    Dim i As Integer
    For i = 0 To 2
        ' Writes each section name as wsStyleHeading2, and then the section body as wdStyleNormal
        Call replace_stuff("<PLACEHOLDER>", section_names(i) & Chr(11) & "<PLACEHOLDER>", wdStyleHeading2)
        Call replace_stuff("<PLACEHOLDER>", section_bodies(i) & Chr(11) & "<PLACEHOLDER>", wdStyleNormal)
    Next i
    Call replace_stuff("<PLACEHOLDER>", Chr(11), wdStyleNormal)

End Sub

输入文档:只包含&lt;PLACEHOLDER&gt;的word文档。

<PLACEHOLDER>

预期输出: 我希望每个标题都以我指定的样式显示,并且可以像这样从导航窗格中查看:

实际输出:但是我实际得到的是像这样wdStyleNormal 风格的一切:

我认为可以通过在每个样式转换之间插入一个段落分隔符来解决问题,但是当我尝试使用 vbCrLFChr(10) &amp; Chr(13)vbNewLine 而不是 chr(11) 时,我现在正在使用,每一行都以这样的带框问号开头:

【问题讨论】:

  • 为什么要在替换的文本中添加“”?文件不包含这些?如果是这样的话,肯定会有更好的编码方式......
  • @CindyMeister,我在每次替换后添加&lt;PLACEHOLDER&gt;,以便 next 查找和替换将能够“找到”它并知道在哪里插入文本。它每次都被替换,最后一个被替换为新行(chr(11)),这就是为什么最终文档中没有出现&lt;PLACEHOLDER&gt;s。这是我想出的方法,但我对 vba 不是很熟悉,所以可能有更好的方法

标签: vba ms-word


【解决方案1】:

更新来自 cmets 关于另一个答案的讨论。下面描述的问题适用于 Word 2016 及更早版本。从 Office 365(可能还有 Word 2019,但尚未确认)开始,Replace 行为已更改为将 ANSI 13“转换”为“真实”段落标记,所以问题中的问题不会出现。

回答

奇怪的格式化行为的原因是使用了Chr(11),它插入了一个新行(Shift + Enter)而不是一个新段落。因此,应用于此文本任何部分的段落样式会以相同的样式格式化整个文本。

在这种特殊情况下(使用Replace),vbCr 或等效的Chr(13) 也不起作用,因为它们并不是真正的 Word 原生段落。段落不仅仅是 ANSI 代码 13 - 它包含段落格式信息。因此,在代码运行时,Word 并没有真正将这些识别为真正的段落标记,并且段落样式分配被应用于“所有内容”。

起作用的是使用字符串^p,它在Word 的查找/替换中是完整段落标记的“别名”。所以,例如:

replace_stuff "<PLACEHOLDER>", section_names(i) & "^p" & "<PLACEHOLDER>", wdStyleHeading2
replace_stuff "<PLACEHOLDER>", section_bodies(i) & "^p" & "<PLACEHOLDER>", wdStyleNormal

但是,与为每个新项目插入占位符并使用查找/替换将占位符替换为文档内容相比,有一种更有效的方法来构建文档。更传统的方法是使用 Range 对象(将其视为不可见的选择)...

将内容分配给Range,对其进行格式化、折叠(如按右箭头进行选择)并重复。这是一个示例,它返回与问题中的(更正的)代码相同的结果:

Sub main()
  Dim rng As Range

  Set rng = ActiveDocument.content
  Dim section_names(2) As String
  section_names(0) = "Introduction"
  section_names(1) = "Background"
  section_names(2) = "Conclusion"

  Dim section_bodies(2) As String
  section_bodies(0) = "This is the body text for the introduction! Fetched from some file."
  section_bodies(1) = "And Background... I have no issue fetching data from the files."
  section_bodies(2) = "And for the conclusion... But I want the styles to 'stick'!"

  Dim i As Integer
  For i = 0 To 2
    BuildParagraph section_names(i), wdStyleHeading2, rng
    BuildParagraph section_bodies(i), wdStyleNormal, rng
  Next i
End Sub

Sub BuildParagraph(para_text As String, para_style As Long, rng As Range)
        rng.Text = para_text
        rng.style = para_style
        rng.InsertParagraphAfter
        rng.Collapse wdCollapseEnd
End Sub

【讨论】:

  • 一个非常描述性的答案!我不知道"^p" 字符。你的两个解决方案都很好用,我将使用 range 方法~
【解决方案2】:

问题是由您使用Chr(11) 引起的,这是手动换行符。这导致所有文本都在一个段落中。应用段落样式时,它适用于整个段落。

Chr(11) 替换为vbCr 以确保每段文本都位于单独的段落中。

【讨论】:

  • 不幸的是,这仍然会导致样式全部合并到最终样式中。
  • 你需要 Chr(13)
  • @CindyMeister 哎呀。读作 vbCrLf。
  • @Freeflow 不,Word 无法正确识别。那是 Chr(13) 和 Chr(10),Word 不会将 Chr(10) 用于任何事情。
  • @CindyMeister 实际上将 Chr(11) 更改为 vbCr 效果很好。我在发布之前测试了我的答案。它是否应该工作是另一回事。
猜你喜欢
  • 2012-03-08
  • 1970-01-01
  • 2014-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-10
  • 2018-01-18
  • 2014-04-06
相关资源
最近更新 更多