无法在Word VBA中获取递归Range.Find以使其工作

时间:2015-04-24 03:46:20

标签: vba recursion ms-word word-vba

我已经暂时搁浅了一段时间,似乎无法想出一个解决方案。我必须通过通配符搜索自定义标记从头到尾搜索文档。为了问题,我们会说{something}当我找到特定匹配时,它会被另一个字符串的内容替换,该字符串可以包含标记。标记必须按照它在最终文档中出现的顺序进行替换 AND 我必须知道每次替换的递归级别。

这基本上就是我提出来的。请注意,ProcessReplacement函数是为示例设计的 - 文本被外部程序替换:

Option Explicit

Private replaced As Integer

Public Sub Demo()

    Dim pos As Range

    Set pos = ActiveDocument.Content
    replaced = 0
    pos.Text = "{fizz}{fizz}{more}{buzz}{buzz}"
    Expand pos

End Sub

Private Sub Expand(incoming As Range, Optional depth = 1)

    Dim sub_range As Range
    Dim end_pos As Long

    end_pos = incoming.End
    With incoming.Find
        .ClearFormatting
        .MatchWildcards = True
        .Forward = True
        .Wrap = wdFindStop
    End With

    Do While incoming.Find.Execute("\{*\}")
        If incoming.Start < incoming.End Then
            Debug.Print "Replaced " & incoming.Text & " at " & depth
            end_pos = end_pos + ProcessReplacement(incoming)
            Set sub_range = incoming.Duplicate
            Expand sub_range, depth + 1
            incoming.End = end_pos
            incoming.Start = sub_range.End - 1
        End If
    Loop

End Sub

Private Function ProcessReplacement(replacing As Range) As Long
    Dim len_cache As Long

    len_cache = Len(replacing.Text)

    If replacing.Text = "{more}" Then
        replacing.Text = "{foo}{evenmore}{bar}"
    ElseIf replacing.Text = "{evenmore}" Then
        'This kind of works.
        replacing.Text = "{fizzbuzz} "
        'This doesn't work at all.
'        replacing.Text = "{fizzbuzz}"
    Else
        replaced = replaced + 1
        replacing.Text = "<" & replaced & ">"
    End If

    ProcessReplacement = Len(replacing.Text) - len_cache
End Function

第一个问题是我无法确定如何将.Find.Execute限制在正确的范围内。这就是文档和输出的样子({fizzbuzz}之后的空格 - 后面会有更多内容):

Document text: <1><2><3><4> <5><6><7>
Output:
Replaced {fizz} at 1
Replaced {fizz} at 1
Replaced {more} at 1
Replaced {foo} at 2
Replaced {evenmore} at 2
Replaced {fizzbuzz} at 3
Replaced {bar} at 2
Replaced {buzz} at 2    <---This was outside of the range at that depth.
Replaced {buzz} at 1

如果我在{fizzbuzz}之后取出空间,它甚至不会匹配,即使我在观察窗口中确认它基本上是该函数在更换后递归时的范围内容。没有空格的输出:

Document text: <1><2><3>{fizzbuzz}<4><5><6>
Output:
Replaced {fizz} at 1
Replaced {fizz} at 1
Replaced {more} at 1
Replaced {foo} at 2
Replaced {evenmore} at 2
Replaced {bar} at 3  <---No clue how this happens - wdFindStop is ignored.
Replaced {buzz} at 3
Replaced {buzz} at 3

预期输出(带或不带空格):

Document text: <1><2><3><4><5><6><7>
Output:
Replaced {fizz} at 1
Replaced {fizz} at 1
Replaced {more} at 1
Replaced {foo} at 2
Replaced {evenmore} at 2
Replaced {fizzbuzz} at 3
Replaced {bar} at 2
Replaced {buzz} at 1
Replaced {buzz} at 1

有人看到我失踪的任何东西吗?

1 个答案:

答案 0 :(得分:2)

Word的Find行为非常奇怪。

在其他特性中,如果您的搜索文本与Range文本的完全匹配匹配,则忽略Wrap选项,并根据此{重新定义搜索范围} {3}}:

  

当Find对象.Execute方法确定要查找的内容与搜索范围完全匹配时,将动态重新定义搜索范围。新搜索范围从旧搜索范围的末尾开始,到文档末尾(或目标storyRange)结束。处理在重新定义的范围内继续。

这就是为什么{fizzbuzz}(带尾随空格)有效 - 它完全匹配。

您需要调整代码才能处理:

  1. Range.Text与通配符搜索完全匹配,和/或:
  2. 致电Execute后,检查Range的开头是,然后预期结束。
  3. 您可以通过在每次Range来电之前和之后以及每次Range.Select作业之前和之后添加Execute声明来查看Text更改操作