Share via

How do I correctly build a complex search query in Word VBA?

Anonymous
2022-11-15T11:41:04+00:00

Hi everyone,

In a report, I need to turn all references to UN documents into hyperlinks. I found exactly how to do this](https://answers.microsoft.com/en-us/msoffice/forum/all/find-and-convert-textnumber-pattern-to-hyperlinks/b55e2fef-e05d-41f2-8367-ac621f379f9b "https://answers.microsoft.com/en-us/msoffice/forum/all/find-and-convert-textnumber-pattern-to-hyperlinks/b55e2fef-e05d-41f2-8367-ac621f379f9b") thanks to @[Jay Freedman. I also learned a lot from https://wordmvp.com/ However, my search strings are more complex and I am grappling with the correct syntax...

Here are examples of all the references I need to find: A/1234/1234, A/1234/1234/Add.1, S/1234/1234, S/1234/1234/Add.1, S/PV.1234, S/PV.1234 (Resumption 1), S/INF/1234/1234, S/PRST/1234/1234, ST/PSCA/1/Add.1, 1234 (1234), 1234 (XVI).

Here is what I came up with so far:

[AS]/[0-9]{1,}/[0-9]{1,}
[AS]/[0-9]{1,}/[0-9]{1,}/Add.[0-9]{1,}
S/PV.[0-9]{1,}
S/PV.[0-9]{1,} \(Resumption [0-9]{1,}\)
S/INF/[0-9]{1,}/[0-9]{1,}
S/PRST/[0-9]{1,}/[0-9]{1,}
ST/PSCA/[0-9]{1,}/Add.[0-9]{1,}
[0-9]{1,} \([0-9]{4}\)
[0-9]{1,} \([IVX]{1,}\)

Individually, each of these work great. But, I have three issues when using a script:

  1. How do I combine them? All of them use the same URL except for the last two which use a different one.
  2. References with and without additionnal parameters: how do I deal with instances like "A/1234/1234" and "A/1234/1234/Add.1"?
  3. References with spaces: how do I remove all spaces in the resulting hyperlink? I tried Trim(strLinkAddr) but it does not work.

For reference, Jay's script:

Option Explicit

Sub MakeHyperlinks()

     Dim rg As Range

     Dim strLinkAddr As String

     strLinkAddr = "https://dtf.custhelp.com/AgentWeb/api/contextmanager/v.32201260002/workspaceContext/workspace/processedPrint/Answer/"

     Set rg = ActiveDocument.Range

     With rg.Find

         .Text = "#^#^#^#^#^#"

         .Wrap = wdFindStop

         While .Execute

             rg.Hyperlinks.Add Anchor:=rg, Address:=strLinkAddr & Right(rg.Text, 5)

             rg.Collapse wdCollapseEnd

             DoEvents

         Wend

     End With

End Sub
Microsoft 365 and Office | Word | For home | Windows

Locked Question. This question was migrated from the Microsoft Support Community. You can vote on whether it's helpful, but you can't add comments or replies or follow the question.

0 comments No comments

Answer accepted by question author

Jay Freedman 207.7K Reputation points Volunteer Moderator
2022-11-15T22:56:01+00:00

There are several major changes from the previous macro to the one below.

  • The wildcard expressions from your post are listed in the string variable strPatterns, each separated from the next by a "pipe" character "|". (The ampersand and underscore at the ends of the first four lines of that statement are the string concatenation character and the line continuation character. The result is one long string. If copying and pasting the code into your macro editor inserts blank lines between the code lines in this group, you must remove them to prevent a syntax error.)
  • The strPatterns string is then loaded into the arrPatterns array by the Split function, which breaks the string at each pipe character.
  • Since you mentioned that the last two expressions need a different URL, these are put into the variables strLinkAddr1 and strLinkAddr2. You'll have to insert the proper URL for strLinkAddr2.
  • A For...Next loop runs through all the entries in arrPatterns. (The array indexes start at 0, not at 1. The UBound function returns the index of the last entry.) The If...Else...End If structure chooses the correct URL from the current value of idx.
  • The MatchWildcards member of the Find object must be set to True so the search expressions will work.
  • As indicated in the "don't add a hyperlink" comment, the name of the style applied to the found range is checked, and the hyperlink is applied only if the style is not already "Hyperlink".
  • The Replace function removes any space characters that exist in the hyperlink's address.

The following code has been tested against the simple example given in your post. You will need to test it on a live document (or a copy of one).

Option Explicit 

Sub MakeHyperlinks() 

     Dim rg As Range 

     Dim strLinkAddr 

     Dim strLinkAddr1 As String 

     Dim strLinkAddr2 As String 

     Dim strPatterns As String 

     Dim arrPatterns() As String 

     Dim idx As Integer 

     'list of all wildcard expressions 

     ' NOTE: for the first two pairs of patterns, the one with the "Add" or "Resumption" 

     '       must come before the one that does not have that part 

     strPatterns = "[AS]/[0-9]{1,}/[0-9]{1,}/Add.[0-9]{1,}|[AS]/[0-9]{1,}/[0-9]{1,}|" & _ 

                   "S/PV.[0-9]{1,} \(Resumption [0-9]{1,}\)|S/PV.[0-9]{1,}|" & _ 

                   "S/INF/[0-9]{1,}/[0-9]{1,}|S/PRST/[0-9]{1,}/[0-9]{1,}|" & _ 

                   "ST/PSCA/[0-9]{1,}/Add.[0-9]{1,}|[0-9]{1,} \([0-9]{4}\)|" & _ 

                   "[0-9]{1,} \([IVX]{1,}\)" 

     'load the expressions into an array 

     arrPatterns = Split(strPatterns, "|") 

     strLinkAddr1 = "https://dtf.custhelp.com/AgentWeb/api/contextmanager/v.32201260002/workspaceContext/workspace/processedPrint/Answer/" 

     strLinkAddr2 = "//someotherplace.com"  '*** insert correct URL here 

     'loop through the patterns in the array 

     For idx = 0 To UBound(arrPatterns) 

        'select second URL for the last two patterns 

        If idx < UBound(arrPatterns) - 1 Then 

            strLinkAddr = strLinkAddr1 

        Else 

            strLinkAddr = strLinkAddr2 

        End If 

        Set rg = ActiveDocument.Range 

        With rg.Find 

            .MatchWildcards = True 

            .Text = arrPatterns(idx)   ' choose the pattern for this pass 

            .Wrap = wdFindStop 

            While .Execute 

                'don't add a hyperlink to a range that is already a hyperlink 

                'for example, A/1234/1234/Add.1 would already have been linked 

                'when A/1234/1234 is found inside it, but it would have Hyperlink style 

                If Not rg.Style = "Hyperlink" Then 

                    rg.Hyperlinks.Add Anchor:=rg, Address:=strLinkAddr & Right(rg.Text, 5) 

                    'remove any spaces 

                    rg.Hyperlinks(1).Address = Replace(rg.Hyperlinks(1).Address, " ", "") 

                    rg.Collapse wdCollapseEnd 

                End If 

                DoEvents 

            Wend 

        End With 

     Next idx 

End Sub

Was this answer helpful?

3 people found this answer helpful.
0 comments No comments

Answer accepted by question author

Jay Freedman 207.7K Reputation points Volunteer Moderator
2022-11-16T13:06:43+00:00

Thank you for the compliment!

A document consists of a number of "storyranges", of which the body text is only one. To search the footnotes as well, a separate search is needed, with the range rg initialized to ActiveDocument.StoryRanges(wdFootnotesStory) instead of ActiveDocument.Range. (Technically, ActiveDocument.Range corresponds to ActiveDocument.StoryRanges(wdMainTextStory).) I've done that below, leaving out the comments for brevity.

Option Explicit 

Sub MakeHyperlinks() 

     Dim rg As Range 

     Dim strLinkAddr 

     Dim strLinkAddr1 As String 

     Dim strLinkAddr2 As String 

     Dim strPatterns As String 

     Dim arrPatterns() As String 

     Dim idx As Integer 

     'list of all wildcard expressions 

     ' NOTE: for the first two pairs of patterns, the one with the "Add" or "Resumption" 

     '       must come before the one that does not have that part 

     strPatterns = "[AS]/[0-9]{1,}/[0-9]{1,}/Add.[0-9]{1,}|[AS]/[0-9]{1,}/[0-9]{1,}|" & _ 

                   "S/PV.[0-9]{1,} \(Resumption [0-9]{1,}\)|S/PV.[0-9]{1,}|" & _ 

                   "S/INF/[0-9]{1,}/[0-9]{1,}|S/PRST/[0-9]{1,}/[0-9]{1,}|" & _ 

                   "ST/PSCA/[0-9]{1,}/Add.[0-9]{1,}|[0-9]{1,} \([0-9]{4}\)|" & _ 

                   "[0-9]{1,} \([IVX]{1,}\)" 

     'load the expressions into an array 

     arrPatterns = Split(strPatterns, "|") 

     strLinkAddr1 = "https://dtf.custhelp.com/AgentWeb/api/contextmanager/v.32201260002/workspaceContext/workspace/processedPrint/Answer/" 

     strLinkAddr2 = "//someotherplace.com"  '*** insert correct URL here 

     'loop through the patterns in the array 

     For idx = 0 To UBound(arrPatterns) 

        'select second URL for the last two patterns 

        If idx < UBound(arrPatterns) - 1 Then 

            strLinkAddr = strLinkAddr1 

        Else 

            strLinkAddr = strLinkAddr2 

        End If 

        Set rg = ActiveDocument.Range 

        With rg.Find 

            .MatchWildcards = True 

            .Text = arrPatterns(idx)   ' choose the pattern for this pass 

            .Wrap = wdFindStop 

            While .Execute 

                'don't add a hyperlink to a range that is already a hyperlink 

                'for example, A/1234/1234/Add.1 would already have been linked 

                'when A/1234/1234 is found inside it, but it would have Hyperlink style 

                If Not rg.Style = "Hyperlink" Then 

                    rg.Hyperlinks.Add Anchor:=rg, Address:=strLinkAddr & Right(rg.Text, 5) 

                    'remove any spaces 

                    rg.Hyperlinks(1).Address = Replace(rg.Hyperlinks(1).Address, " ", "") 

                    rg.Collapse wdCollapseEnd 

                End If 

                DoEvents 

            Wend 

        End With 

        Set rg = ActiveDocument.StoryRanges(wdFootnotesStory) 

        With rg.Find 

            .MatchWildcards = True 

            .Text = arrPatterns(idx) 

            .Wrap = wdFindStop 

            While .Execute 

                If Not rg.Style = "Hyperlink" Then 

                    rg.Hyperlinks.Add Anchor:=rg, Address:=strLinkAddr & Right(rg.Text, 5) 

                    rg.Hyperlinks(1).Address = Replace(rg.Hyperlinks(1).Address, " ", "") 

                    rg.Collapse wdCollapseEnd 

                End If 

                DoEvents 

            Wend 

        End With 

     Next idx 

End Sub

Was this answer helpful?

1 person found this answer helpful.
0 comments No comments

2 additional answers

Sort by: Most helpful
  1. Anonymous
    2022-11-16T13:48:48+00:00

    Hi Jay,

    Thank you. This makes a lot of sense.

    You’re a great master. I feel priviledged.

    Take care.

    Was this answer helpful?

    0 comments No comments
  2. Anonymous
    2022-11-16T11:29:12+00:00

    Hi Jay,

    Thank you for your reply and taking time for the extensive comments that help to understand - and make everything seem so natural and logical! Calling the longer references first and using If Not rg.Style = "Hyperlink" Then is brilliant. You may know the quote, good teachers explain but great teachers inspire.

    I have one additional question: I ran the script on a short extract of the document and realized that it did not capture those references that were in the footnotes. How can I also include the footnotes?

    Was this answer helpful?

    0 comments No comments