Resting Anchor

The Anchorage

Personal website of Gregory K. Maxey, Commander USN (Retired)

Using a Macro to Replace Text Wherever It Appears in a Document
(A Microsoft Word Help & Tip page by Gregory K. Maxey)

DISCLAIMER/TERMS OF USE

The information, illustrations and code contained in my "Microsoft Word Tips" are provided free and without risk or obligation.

Click to acces PayPal Verification Service Click to acces PayPal Verification Service

However, the work is mine. If you use it for commercial purposes or benefit from my efforts through income earned or time saved then a donation, however small, will help to ensure the continued availability of this resource.

If you would like to donate, please use the appropriate donate button to access PayPal. Thank you!

Click to donate British Pound Sterling                   Click to donate US dollars                   Click to donate EU euros

The purpose of this Microsoft Word Tips & Microsoft Word Help page is discuss and provide a VBA solution to find and replace text wherever it may appear in a document.  This content is a modified version of my article on the same topic previously published at the Word MVP FAQ website.  Acknowledgments to Doug Robbins, Peter Hewett and Jonathan West for their contributions to that article.

Background

Using the Find or Replace utility on the Edit menu you can find or replace text "almost" anywhere it appears in the document. If you record that action however, the scope or "range" of the resulting recorded macro will only act on the text contained in the body of the document (or more accurately, it will only act on the part of the document that contains the insertion point). This means that if the insertion point is located in the main body of the document when your macro is executed it will have no effect on text that is in the headers or footers of the document, for example, or in a textbox, footnotes, or any other area that is outside the main body of the document.

In Word 2007 or earlier even the built-in Find & Replace utility has a shortcoming.  For example, text in a textbox located in a header or footer is outside the scope of the Find and Replace utility search range.

There are eleven to seventeen wdStoryType constants that can form the StoryRanges (or parts) of a document. Not all storyranges are used in every document. The seventeen possible storytypes in a Word 2016 document is shown below.

fr_anywhere_1

Basic Code

The comprehensive code to ensure you look for and find text wherever is may be in a document is complex. Accordingly, let’s take it a step at a time to better illustrate the process and identify the issues. In many cases this simpler incremented code will be sufficient for getting the job done.

VBA Script:
Sub FindAndReplaceFirstStoryOfEachType()
Dim rngStory As Range
  For Each rngStory In ActiveDocument.StoryRanges
    With rngStory.Find
      .Text = "find text"
      .Replacement.Text = "I'm found" 
      .Wrap = wdFindContinue 
      .Execute Replace:=wdReplaceAll  
    End With 
  Next   rngStory
lbl_Exit:
  Exit Sub 
End Sub

Site Note IconBonus Tip:  If you are not aware, when use the Selection.Find method, you should specify all of the Find and Replace parameters, such as .Forward = True, because the values are otherwise taken from the Find and Replace dialog's current settings, which are “sticky. This is not necessary when using Range.Find, because the parameters are their default value if you don't specify a value in your code.

The basic macro above has a shortcoming. It only acts on the "first" StoryRange of each of the (eleven-seventeen) StoryTypes.

While a document only has one wdMainTextStory StoryRange, it can have one or more StoryRanges in several of the other StoryTypes. For example, a document may contain multiple text boxes, or multiple sections with un-linked headers or footers.  Each of those multiple elements is a StoryRange in the StoryType.  The basic code only process the first StoryRange in those StoryTypes. 

Intermediate Code

To make sure that the code acts on every StoryRange in each each StoryType, you need to:

VBA Script:
Public Sub FindReplaceAlmostAnywhere()
Dim rngStory As Word.Range
Dim lngValidate As Long
  'Fix the skipped blank Header/Footer problem as provided by Peter Hewett.
  lngValidate = ActiveDocument.Sections(1).Headers(1).Range.StoryType
  'Iterate through all story types in the current document.
  For Each rngStory In ActiveDocument.StoryRanges
    'Iterate through all linked stories.
    Do
      With rngStory.Find
        .Text = "Test"
        .Replacement.Text = "I'm found"
        .Wrap = wdFindContinue
        .Execute Replace:=wdReplaceAll
      End With
      'Get next linked story (if any).
      Set rngStory = rngStory.NextStoryRange
    Loop Until rngStory Is Nothing
  Next
lbl_Exit:
  Exit Sub
End Sub

The VBA "Trickery" mentioned above simply returns the value of the Section One Primary Header StoryType.  This has proven to eliminate the problem VBA has of "jumping" empty unlinked header/footers and continuing to process sequent headers and footers.


There is one remaining shortcoming with the intermediate code above. Like the menu Find and Replace utility in earlier Word versions, this code will miss and fail to process textboxes and shapes anchored to a header/footer StoryRange.

Comprehensive Code

The solution to the header/footer textbox and shape problem is found in the fact that textboxes and shapes are contained in the document’s ShapeRange collection.  First we check the  ShapeRange of each of the six header and footer StoryRanges in each  document section for  for the presence of a shape.  If a shape is found, we then check shape's .TextFrame.TextRange for the .Find.Text parameter.

This final macro contains all of the code to find and replace text “anywhere” in a document. A few enhancements have been added to make it easier to apply the desired find and replace text strings:

VBA Script:
Public Sub FindReplaceAnywhere()
Dim rngStory As Word.Range
Dim strFind As String, strRplc As String
Dim lngValidate As Long
Dim oShp As Shape

  strFind = InputBox("Enter the text that you want to find.", "FIND")
  If strFind = "" Then
    MsgBox "Cancelled by User"
    Exit Sub
  End If
TryAgain:
  strRplc = InputBox("Enter the replacement.", "REPLACE")
  If strRplc = "" Then
    If MsgBox("Do you just want to delete the found text?", _
      vbYesNoCancel) = vbNo Then
      GoTo TryAgain
    ElseIf vbCancel Then
      MsgBox "Cancelled by User."
      Exit Sub
    End If
  End If
  'Fix the skipped blank Header/Footer problem.
  lngValidate = ActiveDocument.Sections(1).Headers(1).Range.StoryType
  'Iterate through all story types in the current document.
  For Each rngStory In ActiveDocument.StoryRanges
    'Iterate through all linked stories.
    Do
      SearchAndReplaceInStory rngStory, strFind, strRplc
      On Error Resume Next
      Select Case rngStory.StoryType
        Case 6, 7, 8, 9, 10, 11
          If rngStory.ShapeRange.Count > 0 Then
            For Each oShp In rngStory.ShapeRange
              If oShp.TextFrame.HasText Then
                SearchAndReplaceInStory oShp.TextFrame.TextRange, strFind, strRplc
              End If
            Next
          End If
        Case Else
          'Do Nothing
      End Select
      On Error GoTo 0
      'Get next linked story (if any)
      Set rngStory = rngStory.NextStoryRange
    Loop Until rngStory Is Nothing
  Next
lbl_Exit:
  Exit Sub
End Sub

Public Sub SearchAndReplaceInStory(ByVal rngStory As Word.Range, _
                                   ByVal strSearch As String, _
                                   ByVal strReplace As String)
    With rngStory.Find
      .ClearFormatting
      .Replacement.ClearFormatting
      .Text = strSearch
      .Replacement.Text = strReplace
      .Wrap = wdFindContinue
      .Execute Replace:=wdReplaceAll
    End With
lbl_Exit:
  Exit Sub
End Sub

Site Note iconNote: This tips page, illustrations and examples were developed using Word 2016. It is wholly functional with Word 2003-2016.

That's it! I hope you have found this tips page useful and informative.

Share

DISCLAIMER/TERMS OF USE

The information, illustrations and code contained in my "Microsoft Word Tips" are provided free and without risk or obligation.

Click to acces PayPal Verification Service Click to acces PayPal Verification Service

However, the work is mine. If you use it for commercial purposes or benefit from my efforts through income earned or time saved then a donation, however small, will help to ensure the continued availability of this resource.

If you would like to donate, please use the appropriate donate button to access PayPal. Thank you!

Click to donate British Pound Sterling                   Click to donate US dollars                   Click to donate EU euros

Search my site or the web using Google Search Engine

Google Search Logo