I'm trying to find a regex string, <XE "i#>, in a Word document.
Background: I'm building an index, and automatically picking up paragraphs to add via another macro. There are some entries that start "i. Automobile - means a car", or "ii. Super - means really good". I want to remove the numbering part from the Index entry, so thought a way to do so would be to look for the {XE "i. Automobile ...} part and just remove the i. using RegEx.
When I search manually for my string, it works fine and picks up the matches. However, my macro doesn't work. When stepping through, then I get to While .Execute, the next step just goes to Wend then End With. It does ask if I want to search from the beginning, so the .Find is working somewhat, but why isn't it finding any matches?
Thanks so much for any advice!
Sub Hide_Roman_Numerals_from_Index()
Dim defText As String
Dim regExSearch As String
Dim oRng As Word.Range, rng As Word.Range
If ActiveWindow.ActivePane.View.ShowAll = False Then
ActiveWindow.ActivePane.View.ShowAll = True
End If
Set oRng = ActiveDocument.Range
'Call ClearFindAndReplaceParameters(oRng)
regExSearch = "<XE ""i#>"
oRng.Find.ClearFormatting
With oRng.Find
.Text = regExSearch
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindAsk
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchAllWordForms = False
.MatchSoundsLike = False
.MatchWildcards = True
While .Execute
Set rng = oRng.Paragraphs(1).Range
rng.Select
Wend
End With
If ActiveWindow.ActivePane.View.ShowAll = True Then
ActiveWindow.ActivePane.View.ShowAll = False
End If
'Call ClearFindAndReplaceParameters(oRng)
End Sub
I think this approach will suit you if I got your problem right.
'BruceWayne
Sub Colorgreenfromw()
Application.ScreenUpdating = False
Dim oPar As Paragraph
Dim oRng As Word.Range
For Each oPar In ActiveDocument.Paragraphs
Set oRng = oPar.Range
With oRng
With .Find
.ClearFormatting
.Font.Color = wdColorGreen
.Replacement.ClearFormatting
.Text = "<XE ""i#>"
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchWildcards = True
.Execute
End With
If .Find.Found Then
Set oRng = oPar.Range
oRng.Font.Color = wdColorGreen
Set oRng = Nothing
End If
End With
Next
End Sub
Related
this is my first post here!
I am new to Microsoft VBA, but I need to write some macros to quickly make the same changes to 200+ documents. I took the Udemy course on Word VBA but I am stuck trying to figure out how to address the following issues:
I need to select all content from beginning of doc up until the first occurrence of the string "following:" including the string itself - the issue is that for each doc, this string will always be in a different position and the portion I want to delete will vary in length. The only guarantee is that it will always be on the first page.
I need to do the same thing for the end of the document - I need to delete all content following the string "Affirmative Defenses" including the string itself - again, this will always be in a different position and will not always be on the last page (unlike issue number 1)
I have written many variations by reading other questions/solutions with no luck. Below is my current version but it does not work.
Sub DeleteBegin()
Dim findRng As Range
Set findRng = ActiveDocument.Range
Dim endPara As Long
With findRng.Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "following."
.Replacement.Text = ""
.Wrap = wdFindStop
.MatchWholeWord = True
.Forward = True
.Execute
If .Found = True Then
endPara = GetParaNum(findRng)
findRng.Start = 0
findRng.End = endPara
End If
Dim capRng As Range
Set capRng = ActiveDocument.Range
capRng.SetRange Start:=0, End:=endPara
capRng.Select
Selection.Delete
End With
End Sub
Function GetParaNum(ByRef r As Object) As Integer
Dim rPara As Object
Dim CurPos As Long
r.Select
CurPos = ActiveDocument.Bookmarks("\startOfSel").Start
Set rPara = ActiveDocument.Range(Start:=0, End:=CurPos)
GetParaNum = rPara.Paragraphs.Count
End Function
Try:
Sub Demo()
Application.ScreenUpdating = False
Dim Rng As Range
With ActiveDocument
Set Rng = .Range(0, 0)
With .Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "following."
.Replacement.Text = ""
.Format = False
.Forward = True
.Wrap = wdFindStop
.Execute
End With
If .Find.Found = True Then
Rng.End = .Duplicate.End
Rng.Delete
End If
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "Affirmative Defenses"
.Replacement.Text = ""
.Format = False
.Forward = True
.Wrap = wdFindStop
.MatchCase = True
.Execute
End With
If .Find.Found = True Then
Set Rng = .Duplicate
Rng.End = ActiveDocument.Range.End
Rng.Delete
End If
End With
End With
Application.ScreenUpdating = True
End Sub
I want to delete a paragraph that starts with string "Page:" from the selection
Here is the sample text that I have:
Page: 28
Page: 44 contains a lot of example. But look up here for the detailed
explanation. This may go for more than one, two or three lines. This
totally depends upon the length of the text
Date: 10 Jan 2018
Some text goes here with Page: 108
I’ve some more text here
Few more
Final Text
Page: 208
This is the end
The code I have so far:
Sub DelPara()
Dim para As Paragraph
With Selection.Range.Find
.ClearFormatting
.Text = "[^13^11]Page:"
.Forward = True
.MatchWildcards = True
.Wrap = wdFindContinue
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchSoundsLike = False
.MatchAllWordForms = False
.Execute
If (Selection.Range.Find = True) Then
para.Range.Delete
End If
End With
End Sub
The output should be
Date: 10 Jan 2018
Some text goes here with Page: 108
I’ve some more text here
Few more
Final Text
This is the end
The code below will search all instances of the search term in the current selection and delete the search term plus the entire paragraph in which the end of the term is located.
The key to this is using two Range objects: one for the original Range to be searched (the selection), the other for the actual search. In this way, the range that performs the actual search can be extended from the end of the last successful search to the end of the original range.
Sub DelPara()
Dim rngFind As Word.Range, rngSel As Word.Range
Dim para As Paragraph
Dim bFound As Boolean
Set rngSel = Selection.Range
Set rngFind = rngSel.Duplicate
With rngFind.Find
.ClearFormatting
.text = "[^13^11]Page:"
.Forward = True
.MatchWildcards = True
.wrap = wdFindContinue
.Format = False
.MatchCase = False
.MatchWholeWord = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
bFound = rngFind.Find.Execute
Do While bFound
rngFind.End = rngFind.paragraphs.Last.Range.End
rngFind.Delete
rngFind.Collapse wdCollapseEnd
rngFind.End = rngSel.End
bFound = rngFind.Find.Execute
Loop
End Sub
All you need is a wildcard Find/Replace with:
Find = ^13Page:[!^13]{1,}
Replace = nothing
No code required. At most, you might need to insert an empty paragraph at the beginning of the document and delete it afterwards - but then only if the first para starts with 'Page:'. Nevertheless, as a macro:
Sub Demo()
Application.ScreenUpdating = False
With ActiveDocument.Range
.InsertBefore vbCr
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "^13Page:[!^13]{1,}"
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.Format = False
.MatchWildcards = True
.Execute Replace:=wdReplaceAll
End With
.Characters.First = vbNullString
End With
Application.ScreenUpdating = True
End Sub
If you want to process only the selected range, change 'ActiveDocument' to 'Selection'.
Consider the following macro, that I got from Macro Recorder:
Sub Macro8()
'
' Macro8 Macro
'
'
Selection.Find.ClearFormatting
Selection.Find.Replacement.ClearFormatting
With Selection.Find.Replacement.Font
.Bold = True
.Color = wdColorGreen
End With
With Selection.Find
.Text = "[0-9]{2}/[0-9]{2}/[0-9]{4}"
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindContinue
.Format = True
.MatchCase = False
.MatchWholeWord = False
.MatchAllWordForms = False
.MatchSoundsLike = False
.MatchWildcards = True
End With
Selection.Find.Execute Replace:=wdReplaceAll
End Sub
How could I get all results and save them to an array?
You do this using Range objects. Think of a Range as being an invisible selection with the important difference that there can be many ranges, but only one selection.
In the code below the search Range (rSearch) is set to the entire document and the Find properties are defined for it, rather than Selection. I changed wrap from wdFindContinue to wdFindStop so that the macro won't start over from the beginning of the document again, and again, and again... And wdReplaceAll needs to be wdReplaceOne so that each found range can be processed.
The Do-loop is where the assignment of the found range to the array (aFoundRanges) takes place. If the search is successful the array is "redimmed" to accept an additional member. The found Range is "duplicated" to the range rFound, which is assigned to the array. The counter is incremented; rFound is re-set*. The search range is re-set to begin at the end of the last "hit" and end at the end of the document.
This loops until Find.Execute is no longer successful.
Sub KeepFoundInArray()
'
Dim rSearch As Word.Range
Dim rFound As Word.Range
Dim aFoundRanges() As Word.Range
Dim counter As Long
Dim bFound As Boolean
Set rSearch = ActiveDocument.content
rSearch.Find.ClearFormatting
rSearch.Find.Replacement.ClearFormatting
With rSearch.Find.Replacement.Font
.Bold = True
.color = wdColorGreen
End With
With rSearch.Find
.Text = "[0-9]{2}/[0-9]{2}/[0-9]{4}"
.Replacement.Text = ""
.Forward = True
.wrap = wdFindStop
.Format = True
.MatchCase = False
.MatchWholeWord = False
.MatchAllWordForms = False
.MatchSoundsLike = False
.MatchWildcards = True
End With
Do
bFound = rSearch.Find.Execute(Replace:=wdReplaceOne)
If bFound Then
ReDim Preserve aFoundRanges(counter)
Set rFound = rSearch.Duplicate
Set aFoundRanges(counter) = rFound
Set rFound = Nothing
counter = counter + 1
rSearch.Collapse wdCollapseEnd
rSearch.End = ActiveDocument.content.End
End If
Loop While bFound
Debug.Print UBound(aFoundRanges)
End Sub
It's necessary to duplicate the found range - if you don't, that range will be written to the array. And it will always reflect the current range rSearch - what the array members "point to" will be that Range. A duplicate copies the Range object and makes the copy independent of the original. That's also why it's a good idea to re-set rFound(Set rFound = Nothing) - to ensure the next instance of rSearch.Duplicate is again independent.
I have a text with five 'XX' scattered at different places. I'd like to
replace the first instance of XX by 1., the second instance by 2. and
so, until replacing the fifth instance by 5. I tried to use the
following code without success:
Selection.Find.ClearFormatting
Selection.Find.Replacement.ClearFormatting
With Selection.Find
.Text = "XX"
.Replacement.Text = "1."
.Execute Replace:=wdReplaceOne
.Forward = True
.Text = "XX"
.Replacement.Text = "2."
.Execute Replace:=wdReplaceOne
.Forward = True
[...]
.Text = "XX"
.Replacement.Text = "5."
.Execute Replace:=wdReplaceOne
.Wrap = wdFindStop
End With
End Sub
How can I modify the above code, or what else should I do to get these substitutions? If I use "sed" on a text file, I'd simply do: s/XX/1./1, s/XX/2./2, s/XX/3./3, etc.
What you can do is use a For...Next loop to increment a counter, using the counter as the replacement text. This will save having to write lots of repeated code, as the first code sample shows.
The code can be made more flexible, for any number of occurrences of the search term, by using a Do...Until loop that repeats until no more instances of the search term are found. This variation is in the second code example.
Both variations contain code to search either the entire document or the current selection. Just comment out the one you don't need and remove the comment from the one you do...
Sub FindAndReplaceWithNumbers()
Dim rngDoc As word.Range, rngFind As word.Range
Dim findString As String
Dim counter As Long
Dim found As Boolean
findString = "XX"
'To search the entire document
'Set rngDoc = ActiveDocument.content
'To search a selection, only
Set rngDoc = Selection.Range
Set rngFind = rngDoc.Duplicate
With rngFind.Find
.ClearFormatting
.Replacement.ClearFormatting
.wrap = wdFindStop
.Forward = True
.Text = findString
End With
For counter = 1 To 5
With rngFind.Find
.Replacement.Text = CStr(counter) & "."
found = .Execute(Replace:=wdReplaceOne)
End With
rngFind.End = rngDoc.End
Next
End Sub
Sub FindAndReplaceWithNumbers()
Dim rngDoc As word.Range, rngFind As word.Range
Dim findString As String
Dim counter As Long
Dim found As Boolean
findString = "XX"
counter = 1
'To search the entire document
'Set rngDoc = ActiveDocument.content
'To search a selection, only
Set rngDoc = Selection.Range
Set rngFind = rngDoc.Duplicate
With rngFind.Find
.ClearFormatting
.Replacement.ClearFormatting
.wrap = wdFindStop
.Forward = True
.Text = findString
End With
Do
With rngFind.Find
.Replacement.Text = CStr(counter) & "."
found = .Execute(Replace:=wdReplaceOne)
End With
rngFind.End = rngDoc.End
counter = counter + 1
Loop Until Not found
End Sub
Simpler and faster:
Sub Demo()
Application.ScreenUpdating = False
Dim i As Long
With ActiveDocument.Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "XX"
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.MatchWildcards = True
.Execute
End With
Do While .Find.Found
i = i + 1
.Text = i
.Collapse wdCollapseEnd
.Find.Execute
Loop
End With
Application.ScreenUpdating = True
MsgBox i & " records updated."
End Sub
To limit the code's scope to a Selection, you could use:
Sub Demo()
Application.ScreenUpdating = False
Dim Rng As Range, i As Long
With Selection
Set Rng = .Range
With .Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "XX"
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindStop
.MatchWildcards = True
.Execute
End With
Do While .Find.Found
If .InRange(Rng) Then
i = i + 1
.Text = i
Else
Exit Do
End If
.Collapse wdCollapseEnd
.Find.Execute
Loop
End With
End With
Application.ScreenUpdating = True
MsgBox i & " records updated."
End Sub
Code to highlight italic text:
Sub Bold_Italic()
Dim rng As Range
Set rng = ActiveDocument.Range
rng.Collapse Direction:=wdCollapseStart
rng.Find.ClearFormatting
rng.Find.Font.Italic = True
rng.Find.Replacement.ClearFormatting
rng.Find.Replacement.Highlight = True
rng.Find.Replacement.Font.Color = wdColorRed
With rng.Find
.Text = ""
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindContinue
.Format = True
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
rng.Find.Execute Replace:=wdReplaceAll
End Sub
How can i highlight the whole paragraph or make selected for a paragraph?
Actually, i want to copy and paste paragraph by paragraph to another document.
I believe you're looking for range.select
Sub Macro()
Dim i As Integer
For i = 1 To ActiveDocument.Paragraphs.Count
Dim range As range
Set range = ActiveDocument.Paragraphs(i).range
'range.Characters.Count > 1 means there is text in the paragraph
If range.Characters.Count > 1 Then
'Handle the desired operation with the paragraph text
range.Select
MsgBox (range.Text)
End If
Next i
End Sub