none
How to search a range in a document? RRS feed

  • Question

  • Hello Support,

    I would appreciate if you can help me with the following task.  I am trying to define and search a range in a document.  This is how I am trying to define and use the range. When the user clicks on a macro button on the ribbon, the macro will record the current insertion point then allows the user to do whatever they need to do  When the user press the Enter key (I will use another macro to reassign the Enter Key functionality), the macro will record the current insertion point. So I want to use these two points to create the search range which I will search for three empty paragraph marks. If three consecutive paragraph marks are found in the range, then replace them with two paragraph marks.

    This is what I tried but not getting it to work.

    Sub SearchTest()

    Dim oRangePointA As Range

    Dim oRangePointB As Range

    Dim oMyRange As Range

    'record the current insertion point as soon as user clicks button.

    ' This point A

    Set oRangePointA = Selection.Range

    '******User do stuff******

    'Record current insertion point as soon as Enter Key is pressed.

    ' This is point B

    Set oRangePointB = Selection.Range ' get current cursor position

    ' create search range

    Set oMyRange = ActiveDocument.Range(oRangePointA.Start, oRangePointB.End)

    MsgBox "THIS IS MY RANGE TEST:   " & oMyRange

        oMyRange.Find.ClearFormatting

        oMyRange.Find.Replacement.ClearFormatting

        With oMyRange.Find

            .Text = "^p^p^p"

            .Replacement.Text = "^p^p"

            .Forward = True

            .Wrap = wdFindContinue

            .Format = False

            .MatchCase = False

            .MatchWholeWord = False

            .MatchWildcards = False

            .MatchSoundsLike = False

            .MatchAllWordForms = False

        End With

    If .Found Then

    Replace (wdReplaceAll) 'replace ^p^p^p with p^p

    Selection.ParagraphFormat.Reset ' reset the paragraph style format

    End If

    End Sub

    Saturday, June 13, 2015 5:49 PM

Answers

  • A two-macro approach might be coded as:

    Option Explicit
    Const StrBkMk As String = "SearchStart"

    Sub SearchStart()
    ActiveDocument.Bookmarks.Add Name:=StrBkMk, Range:=Selection.Range
    End Sub

    Sub SearchTest()
    With ActiveDocument
      If .Bookmarks.Exists(StrBkMk) Then
        With .Range(.Bookmarks(StrBkMk).Range.Start, Selection.Range.End).Find
          .ClearFormatting
          .Replacement.ClearFormatting
          .Text = "^p^p^p"
          .Replacement.Text = "^p^p"
          .Forward = True
          .Wrap = wdFindStop
          .Format = False
          .MatchCase = False
          .MatchWholeWord = False
          .MatchWildcards = False
          .MatchSoundsLike = False
          .MatchAllWordForms = False
          .Execute Replace:=wdReplaceAll
        End With
        .Bookmarks(StrBkMk).Delete
      End If
    End With
    End Sub

    In this scenario, you'd run the SearchStart macro to set the bookmark at the start of the range you want to work with. Then, when you're ready to run the SearchTest macro, simply position the insertion point wherever you want the execution to end.


    Cheers
    Paul Edstein
    [MS MVP - Word]

    • Marked as answer by L.HlModerator Wednesday, June 24, 2015 11:36 PM
    Monday, June 15, 2015 2:09 AM

All replies

  • Once an ordinary macro is running, you can't suspend its operation to access the document. You would need to use a modeless userform for that, but then you'd need to use a button on the userform itself to resume its operations.

    Is there a reason your user can't simply select the appropriate range and use Find/Replace (whether macro-driven or otherwise) to remove the extraneous paragraph marks after editing? A macro for that might be:

    Sub SearchTest()
    With Selection.Find
      .ClearFormatting
      .Replacement.ClearFormatting
      .Text = "^p^p^p"
      .Replacement.Text = "^p^p"
      .Forward = True
      .Wrap = wdFindStop
      .Format = False
      .MatchCase = False
      .MatchWholeWord = False
      .MatchWildcards = False
      .MatchSoundsLike = False
      .MatchAllWordForms = False
      .Execute Replace:=wdReplaceAll
    End With
    End Sub


    Cheers
    Paul Edstein
    [MS MVP - Word]

    Sunday, June 14, 2015 12:57 PM
  • Paul,

    Thank you for responding, but what you provided is not what I am looking for.  I want to be able to define a range in the document and search it for the 3 empty paragraphs and replace them with 2 paragraphs. And no, the user won't be selecting his own range to apply the find/replace command.  So you understand, the search range I am trying code will be part of another macro. Basically, whenever the user press the Enter Key, the macro will automatically create the range and search it for the 3 empty paragraphs and replace them with two paragraphs. My initial request stated how I was thinking of creating the range. I am working on the Enter Key part and just need help with defining and searching the range.

    Sunday, June 14, 2015 5:11 PM
  • Hi Fox

    From your problem description, it sounds like you already plan two separate macros - one for the start and one for the end-point to be searched.

    My recommendation would be for the first macro to set a BOOKMARK at the current selection. You can then use the Bookmark.Range.Start to get the beginning of the selection in the second macro in the line Set oMyRange.

    Theoretically, it would be possible to declare a global variable for the first Range object, but global variables can be tricky (volatile), so my preference would definitely be the bookmark. If you don't want to leave a stray bookmark in the document, simply delete after you Set oMyRange.


    Cindy Meister, VSTO/Word MVP, my blog

    Sunday, June 14, 2015 5:37 PM
    Moderator
  • Cindy,

    It will eventually be one macro.  This is how I want it to work. When user clicks the button on the ribbon, it kicks of the macro which will record the location of the insertion point, monitor the press of the EnterKey. when the user press the enter key, it macro creates a range and search it for the multiple empty paragraph marks. If it doesn't find what we reach for it continue to monitor the press of the EnterKey and continue while it is false. I feel like I am pretty close and just need the range part to work.  The Range is not always in the location of the document, so I don't know if I can use bookmark to do it.

    Sunday, June 14, 2015 6:17 PM
  • Hi Fox

    As Paul explained, it is not possible to interrupt a VBA macro. It simply cannot be done.

    You can use a macro to re-map the Enter key to a different macro, so that creating the range and doing the Find/Replace executes until you remove the re-mapping, each time Enter is pressed. But the Enter key needs to call a different macro.

    <<The Range is not always in the location of the document, so I don't know if I can use bookmark to do it.>>

    I don't understand what you're saying, here...


    Cindy Meister, VSTO/Word MVP, my blog

    Sunday, June 14, 2015 6:47 PM
    Moderator
  • Ok, I understand the explanation about using two macros for this, so can you simple show me how to create and search a range in a document? Regarding the part you didn't understand, I was trying explain that the define range is Not always going to be the same start and end point location in the document. So, we need variables to record them.
    Sunday, June 14, 2015 7:06 PM
  • A two-macro approach might be coded as:

    Option Explicit
    Const StrBkMk As String = "SearchStart"

    Sub SearchStart()
    ActiveDocument.Bookmarks.Add Name:=StrBkMk, Range:=Selection.Range
    End Sub

    Sub SearchTest()
    With ActiveDocument
      If .Bookmarks.Exists(StrBkMk) Then
        With .Range(.Bookmarks(StrBkMk).Range.Start, Selection.Range.End).Find
          .ClearFormatting
          .Replacement.ClearFormatting
          .Text = "^p^p^p"
          .Replacement.Text = "^p^p"
          .Forward = True
          .Wrap = wdFindStop
          .Format = False
          .MatchCase = False
          .MatchWholeWord = False
          .MatchWildcards = False
          .MatchSoundsLike = False
          .MatchAllWordForms = False
          .Execute Replace:=wdReplaceAll
        End With
        .Bookmarks(StrBkMk).Delete
      End If
    End With
    End Sub

    In this scenario, you'd run the SearchStart macro to set the bookmark at the start of the range you want to work with. Then, when you're ready to run the SearchTest macro, simply position the insertion point wherever you want the execution to end.


    Cheers
    Paul Edstein
    [MS MVP - Word]

    • Marked as answer by L.HlModerator Wednesday, June 24, 2015 11:36 PM
    Monday, June 15, 2015 2:09 AM
  • Hi Fox

    <<I was trying explain that the define range is Not always going to be the same start and end point location in the document. So, we need variables to record them.>>

    Oh, I understood that and it's why I suggested setting a bookmark - see my first reply. Then see Paul's proposed code, which incorporates my suggestion.


    Cindy Meister, VSTO/Word MVP, my blog

    Monday, June 15, 2015 6:11 PM
    Moderator
  • Paul,

    Thank you for doing the code!  Your code is what I really needed. With your help I can make magic when I put the parts together. I tested the code and the only thing I need at the end of the code is some to the effect of "If  ^p^P is found then do something else do this other thing.  I tried the following code but it did not work. Any help with that line? Thanks

    If Selection.Find.Found Then
    MsgBox "This is just a test. I found it."

    ' disable EnterKey function code goes here.

    exit sub

    else

    ' Leave temp EnterKey

    end if

    Monday, June 15, 2015 10:39 PM
  • Hi Fox

    <<I was trying explain that the define range is Not always going to be the same start and end point location in the document. So, we need variables to record them.>>

    Oh, I understood that and it's why I suggested setting a bookmark - see my first reply. Then see Paul's proposed code, which incorporates my suggestion.


    Cindy Meister, VSTO/Word MVP, my blog

    Hey Cindy,

    Yes, I see and you were correct, but I didn't know and when you don't know something... you don't just know what you don't know.  However, I appreciate your help and explanation, and we are getting there.  You guys are awesome!

    Monday, June 15, 2015 10:46 PM
  • It's not clear to me whether you want something that's interactive for all found instances of ^p^p^p in the search range, or something that's interactive only for an instance of ^p^p in the search range in the event there is no ^p^p^p in the search range. Assuming the former, you could use code like:

    Sub SearchTest()
    Dim RngFnd As Range, RngSel As Range, Rslt
    With ActiveDocument
      If .Bookmarks.Exists(StrBkMk) Then
        Set RngSel = Selection.Range
        Set RngFnd = .Range(.Bookmarks(StrBkMk).Range.Start, Selection.Range.End)
        With RngFnd.Duplicate
          With .Find
            .ClearFormatting
            .Replacement.ClearFormatting
            .Text = "^p^p^p"
            .Forward = True
            .Wrap = wdFindStop
            .Format = False
            .MatchCase = False
            .MatchWholeWord = False
            .MatchWildcards = False
            .MatchSoundsLike = False
            .MatchAllWordForms = False
            .Execute
          End With
          Do While .Find.Found
            If .InRange(RngFnd) Then
              .Duplicate.Select
              Rslt = MsgBox("Trim this block?", vbYesNoCancel)
              If Rslt = vbCancel Then Exit Do
              If Rslt = vbYes Then .Characters.Last.Delete
            Else
              Exit Do
            End If
          .Collapse wdCollapseEnd
          .Find.Execute
        Loop
        End With
        .Bookmarks(StrBkMk).Delete
        RngSel.Select
      End If
    End With
    Set RngSel = Nothing: Set RngFnd = Nothing
    End Sub

    As you can see, adding conditional processing requires significantly more code.

    If all you require is something to find ^p^p before the code exits, you'll need to tell us whether you're looking for that anywhere in the original search range (bearing in mind that you may have just finished changing multiple instances of ^p^p^p to ^p^p) or something else.


    Cheers
    Paul Edstein
    [MS MVP - Word]

    Monday, June 15, 2015 11:29 PM
  • Hi Paul,
    Thank you for all your efforts and hard work.  I don't think I want something that's interactive. The code you provided previously seems to work closer to what I want. It is doing the find and replace correctly, but at the end of your code, I just need the following.

    If your code finds what we search for (true) then
      do my other commands/statement

    Else

    It's frustrating that something like this that's easy or already exist in WordPerfect is so much more rigmarole to work in Word. All I am trying to do is get the Enterkey to work similar to how it works when it's in the bullet list or Number list mode.  I can send you the complete code, so you can see my intent. Sorry, I am just frustrated and venting.

    Tuesday, June 16, 2015 2:26 AM
  • In that case, after:

          .Execute Replace:=wdReplaceAll

    insert something along the lines of:

          If .Found = True Then
            MsgBox "Found some!"
          Else
            MsgBox "None found!"
          End If


    Cheers
    Paul Edstein
    [MS MVP - Word]

    Tuesday, June 16, 2015 2:51 AM
  • Paul,

    I get it to work once when it finds what I searched for, but when it does not find what we are searching for, and I press the Enter key, it does NOT provide a carriage return or paragraph.  I think it just need a tweek, but I can't figure out what it needs.  Here is the complete code.  Run the "SetupEnterKeyMacro" routine first.

    Option Explicit
     Const StrBkMk As String = "SearchStart"

    Sub SearchStart()
     ActiveDocument.Bookmarks.Add Name:=StrBkMk, Range:=Selection.Range
     End Sub

    Sub SearchForParagraph()
    ' This macro searches for two empty paragraph marks
    ' within a range and replace them with one
    ' and resets the final paragraph mark direct formatting
     With ActiveDocument
       If .Bookmarks.Exists(StrBkMk) Then
         With .Range(.Bookmarks(StrBkMk).Range.Start, Selection.Range.End).Find
           .ClearFormatting
           .Replacement.ClearFormatting
           .Text = "^p^p"
           .Replacement.Text = "^p"
           .Forward = True
           .Wrap = wdFindStop
           .Format = False
           .MatchCase = False
           .MatchWholeWord = False
           .MatchWildcards = False
           .MatchSoundsLike = False
           .MatchAllWordForms = False
           .Execute Replace:=wdReplaceAll
        
         If .Found = True Then
             MsgBox "Found some!"
            
             Selection.Paragraphs.Reset ' reset the paragraph to default style
            
             'disable the EnterKey function
              FindKey(KeyCode:=BuildKeyCode(wdKeyReturn)).Disable
             ActiveDocument.Bookmarks(StrBkMk).Delete
        Else
             MsgBox "None found!"
       
        End If
       
        End With
       End If
     End With
     End Sub

    Sub SetupEnterKeyMacro()
    'This macro attaches the EnterKeyMacro macro to the ENTER key,
    'thereby reprogramming the function of the key when it is used
    '
    ' https://support.microsoft.com/en-us/kb/211219
    '
     ' Do Not protect the template containing these macros.
       CustomizationContext = ActiveDocument.AttachedTemplate
       ' Bind the ENTER key to the EnterKeyMacro.
       KeyBindings.Add KeyCode:=BuildKeyCode(wdKeyReturn), _
       KeyCategory:=wdKeyCategoryMacro, Command:="SearchForParagraph"
       ' Reprotect the document with Forms protection.
       ''ActiveDocument.Protect Type:=wdAllowOnlyFormFields, NoReset:=True

    Application.Run macroName:="SearchStart"

    End Sub

     

    Tuesday, June 16, 2015 3:43 AM
  • From what I understand, I think you need to insert:

    Call SetupEnterKeyMacro

    immediately before or after:

    MsgBox "None found!"

    to ensure the Enter key gets (re)programmed whenever a match isn't found.


    Cheers
    Paul Edstein
    [MS MVP - Word]

    Tuesday, June 16, 2015 4:20 AM
  • Paul,

    I thought we were close to a solution, but that didn't do it.  Any more idea or suggestion?

    Wednesday, June 17, 2015 2:20 AM
  • Your code suggests you're trying to re-set the Enter Key to its normal behaviour when a match is found. As I understand it, you want to restore/preserve the Enter key re-assignment when a match is not found. In that case, calling the SetupEnterKeyMacro macro should work.

    However, in your previous post you also said "but when it does not find what we are searching for, and I press the Enter key, it does NOT provide a carriage return or paragraph." If that means you want to cancel the re-assignment, then you need to disable the EnterKey function in the Else statement. If that means you want to disable the EnterKey function in either case, you may as well skip the If test and just disable the EnterKey function directly.


    Cheers
    Paul Edstein
    [MS MVP - Word]

    Wednesday, June 17, 2015 2:47 AM
  • I tried the ways you suggested... still no luck. How do they get the EnterKey to work the way it works for bullet list and number list?
    Wednesday, June 17, 2015 4:02 AM
  • I suggest you take another look at: https://support.microsoft.com/en-us/kb/211219 . Your code for restoring the Enter Key's behaviour needs to be the same as in the AutoClose macro there.

    Cheers
    Paul Edstein
    [MS MVP - Word]

    Wednesday, June 17, 2015 4:23 AM
  • Hi Fox

    <<How do they get the EnterKey to work the way it works for bullet list and number list?>>

    Microsoft programmed it that way. This is proprietary functionality (falls in the category AutoFormat As You Type) built-into the Word UI, but it's not exposed to the developer or publicly documented. And it's also not something the user can turn off - unfortunately!


    Cindy Meister, VSTO/Word MVP, my blog

    Wednesday, June 17, 2015 7:15 PM
    Moderator