2015-04-24 56 views
4

我一直在這裏徘徊了一段時間,似乎無法想出一個解決方案。我必須從頭到尾搜索文檔,並使用通配符搜索自定義標記。爲了這個問題,我們會說{something}當我找到一個特定的匹配項時,它會被替換爲另一個字符串的內容,其中也包含包含標記。標記必須按照它在最終文檔中出現的順序進行替換,我必須知道每個替換的遞歸級別。無法在Word VBA中獲得遞歸Range.Find的工作

這基本上是我想出來的。注意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 

有人看到什麼我失蹤?

+0

爲什麼之前沒有展開替換字符串(S)* *他們代入該文件? –

+0

@TimWilliams - 我希望我可以,但替換字符串也可以包含除標記以外的其他格式化文本。這實際上是我的第一個方法,但它完全摧毀了文檔格式。 – Comintern

回答

2

單詞的Find行爲很奇怪。

在其他的特殊性,如果你的搜索文本是準確比賽爲Range的文本,然後將包裹選項將被忽略,並且搜索範圍被重新定義爲每本article

當Find對象.Execute方法確定要查找的內容與搜索範圍完全匹配,搜索範圍將被動態地重新定義。新的搜索範圍從舊搜索範圍的末尾開始,到文檔末尾(或目標storyRange)結束。處理在重新定義的範圍內繼續。

這就是爲什麼{fizzbuzz}(與尾隨的空間)的作品 - 這是不是完全匹配。

你需要去適應你的代碼來處理:

  1. Range.Text是通配符搜索的精確匹配,和/或:
  2. 調用Execute後,檢查Range的開局之前預計結束。

您可以通過之前和每一個Execute調用後和之前和之後的每Text分配添加Range.Select聲明見行動Range變化