Highlighting specific words within a selected range - vba

I am trying to select a range between two words, find a word within the found range and finally color that word.
In the image I want to select range between "Observation" and "Supporting Information" and then search for "Management" words and color them red.
With my code I am able to highlight the first occurrence of the word.
Sub RevisedFindIt4()
' Purpose: highlight the text between (but not including)
' the words "Observation:" and "Supporting Information:" if they both appear.
Dim rng1 As Range
Dim rng2 As Range
Dim rngFound As Range
On Error Resume Next
Application.DisplayAlerts = False
Application.ScreenUpdating = False
Set rng1 = ActiveDocument.Range
If rng1.Find.Execute(FindText:="Observation:") Then
Set rng2 = ActiveDocument.Range(rng1.End, ActiveDocument.Range.End)
If rng2.Find.Execute(FindText:="Supporting Information:") Then
Set rngFound = ActiveDocument.Range(rng1.End, rng2.Start)
If rngFound.Find.Execute(FindText:="Management") Then
rngFound.Select
Selection.Range.HighlightColorIndex = wdRed
End If
End If
End If
Selection.HomeKey wdStory
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub

A modified version of your code using Find to highlight the text.
Sub RevisedFindIt4()
' Purpose: highlight the text between (but not including)
' the words "Observation:" and "Supporting Information:" if they both appear.
Dim rng1 As Range
Dim rng2 As Range
Dim rngFound As Range
Dim highlightIndex As Long
Application.DisplayAlerts = False
Application.ScreenUpdating = False
'capture current highlight color so that it can be reset later
highlightIndex = Options.DefaultHighlightColorIndex
Options.DefaultHighlightColorIndex = wdRed
Set rng1 = ActiveDocument.Range
If rng1.Find.Execute(FindText:="Observation:") Then
Set rng2 = ActiveDocument.Range(rng1.End, ActiveDocument.Range.End)
If rng2.Find.Execute(FindText:="Supporting Information:") Then
Set rngFound = ActiveDocument.Range(rng1.End, rng2.Start)
With rngFound.Find
.Replacement.highlight = True
.Execute Replace:=wdReplaceAll, Forward:=True, FindText:="Management", ReplaceWith:="", Format:=True
End With
End If
End If
Options.DefaultHighlightColorIndex = highlightIndex
Application.ScreenUpdating = True
Application.DisplayAlerts = True
End Sub

The Find method in word can be a bit tricky to manage. What you want to achieve must be done with two searches inside a loop. The first search finds the next 'Observation:', the Second Finds the following 'Supporting Information:'. You then use the end of the first search and the start of the second search to generate the range that needs to be made 'wdRed'
The following code works well on my PC
Option Explicit
Sub RevisedFindIt4()
' Purpose: highlight the text between (but not including)
' the words "Observation:" and "Supporting Information:" if they both appear.
'Application.DisplayAlerts = False
'Application.ScreenUpdating = False
Dim myOuterRange As Word.Range
Set myOuterRange = ActiveDocument.StoryRanges(wdMainTextStory)
With myOuterRange
Do
With .Find
.ClearFormatting
.MatchWildcards = True
.Text = "(Observation)([: ]{1,})(^13)"
.Wrap = wdFindStop
If Not .Execute Then Exit Do
End With
Dim mystart As Long
mystart = .End
.Collapse direction:=wdCollapseEnd
.Move unit:=wdCharacter, Count:=1
myOuterRange.End = ActiveDocument.StoryRanges(wdMainTextStory).End
With .Find
.ClearFormatting
.MatchWildcards = True
.Text = "^13Supporting Information"
.Wrap = wdFindStop
If Not .Execute Then Exit Do
End With
Dim myEnd As Long
myEnd = .Start
ActiveDocument.Range(mystart, myEnd).Font.ColorIndex = wdRed
.Collapse direction:=wdCollapseEnd
.Move unit:=wdCharacter, Count:=1
myOuterRange.End = ActiveDocument.StoryRanges(wdMainTextStory).End
Loop
End With
'Application.ScreenUpdating = True
'Application.DisplayAlerts = True
End Sub
UPDATE
This is the code I first wrote. I blame a biscuit (cookie) shortage for misreading the post the second time and revising my code to the first provided.
Sub RevisedFindIt4()
' Purpose: highlight the text between (but not including)
' the words "Observation:" and "Supporting Information:" if they both appear.
'Application.DisplayAlerts = False
'Application.ScreenUpdating = False
Dim myOuterRange As Word.Range
Set myOuterRange = ActiveDocument.StoryRanges(wdMainTextStory)
With myOuterRange
Do
With .Find
.ClearFormatting
.MatchWildcards = True
.Text = "(Observation:)(*)(Supporting Information:)"
.Wrap = wdFindStop
If Not .Execute Then Exit Do
End With
Dim myInnerRange As Word.Range
Set myInnerRange = .Duplicate
With myInnerRange
With .Find
.Text = "Management"
.Replacement.Font.ColorIndex = wdRed
.Wrap = wdFindStop
.Execute Replace:=wdReplaceAll
End With
End With
.Collapse Direction:=wdCollapseEnd
.Move unit:=wdCharacter, Count:=1
myOuterRange.End = ActiveDocument.StoryRanges(wdMainTextStory).End
Loop
End With
'Application.ScreenUpdating = True
'Application.DisplayAlerts = True
End Sub

Related

Extract in-text citation inside word documents

my purpose is to find author and the year (four digit) inside parenthesis in a word document through regex or wildcards and format the color (change from black to red) to select them through select similar text
my sample to change italic and only all text inside parenthesis:
Dim Rng As Range
Dim n As Long
Application.ScreenUpdating = False
n = Selection.End
With Selection.Find
.MatchWildcards = True
.ClearFormatting
.Wrap = wdFindStop
.text = "\(*\)"
Do While .Execute
Set Rng = Selection.Range
If Rng.Start > n Then Exit Do
Rng.MoveStart unit:=wdCharacter, count:=1
Rng.MoveEnd unit:=wdCharacter, count:=-1
Rng.Font.Italic = True
Loop
End With
Application.ScreenUpdating = True
End Sub
The following code may point you in the right direction
Option Explicit
Sub Test()
SetAuthorTextColour WdColorIndex.wdRed
End Sub
Sub SetAuthorTextColour(ByVal ipColour As WdColorIndex)
Dim myText As Word.Range
With ActiveDocument.StoryRanges(wdMainTextStory)
Do
With .Find
.MatchWildcards = True
.Text = "([(])(*)([0123456789]{4,4})(*)([)])"
.ClearFormatting
.Format = True
.Wrap = wdFindStop
.Execute
End With
If .Find.Found Then
Set myText = .Duplicate
myText.MoveStart unit:=wdCharacter, Count:=1
myText.MoveEnd unit:=wdCharacter, Count:=-1
' you may wish to change to using colorindex as
' I think color is deprecated.
myText.Font.ColorIndex = ipColour
End If
Loop While .Find.Found
End With
End Sub

VBA Word: Applying Character Style to first two words of specific paragraph style

I would like to apply a character style ("Bold Italics") to the first two words of all paragraphs set in the "3 Species" style in MS Word (and later, I'd also like another macro to do same for all the words after the second tab in a different style). I know how to do all this in InDesign, but I'd like it set up in the original Word documents before they get flowed into InDesign.
I'm new at this and can't figure out how to apply it to only the first two words. I did get it to apply the character style to the whole paragraph or to a specific word in that style. It seems like it ought to be simple, but I've only learned to use find and replace type functions so far, and I imagine I will have to use the Range functions, which I don't understand yet. Thanks for any help!
Sub Add_Character_Style()
'
' Add_Character_Style Macro
'
Selection.Find.ClearFormatting
Selection.Find.Replacement.ClearFormatting
With Selection.Find
.Style = "3 Species"
.Text = ""
.Replacement.Text = ""
.Replacement.Style = "Bold Italics"
.Forward = True
.Wrap = wdFindContinue
.Format = True
.MatchCase = False
.MatchWholeWord = False
.MatchWildcards = False
.MatchSoundsLike = False
.MatchAllWordForms = False
End With
Selection.Find.Execute Replace:=wdReplaceAll
End Sub
For example:
Sub Demo()
Application.ScreenUpdating = False
With ActiveDocument.Range
With .Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = "<*>[,. ^s^t]#<*>"
.Style = "3 Species"
.Replacement.Text = ""
.Format = True
.Forward = True
.Wrap = wdFindStop
.MatchWildcards = True
End With
Do While .Find.Execute
.Style = "Bold Italics"
.Start = .Paragraphs(1).Range.End
Loop
End With
Application.ScreenUpdating = True
End Sub
Try this:
Sub Add_Character_Style()
Dim p As Paragraph
Dim doc As Document: Set doc = ActiveDocument
For Each p In doc.Paragraphs
p.Range.Select
Selection.Collapse Direction:=wdCollapseStart
Selection.MoveRight Unit:=wdWord, Count:=2, Extend:=wdExtend
With Selection
If .Style = "3 Species" Then .Style = "Bold Italic"
End With
Next p
End Sub
EDIT:
To avoid use of the Selection object (Timothy Rylatt)
Sub Add_Character_Style()
Dim p As Paragraph
Dim doc As Document: Set doc = ActiveDocument
Dim rng As Range
For Each p In doc.Paragraphs
If p.Range.Style = "3 Species" Then
Set rng = p.Range
With rng
.Collapse Direction:=wdCollapseStart
.MoveEnd Unit:=wdWord, Count:=2
.Style = "Bold Italics"
End With
End If
Next p
End Sub
FURTHER EDIT per macropod:
Sub Add_Character_Style()
Application.ScreenUpdating = False
Dim Para As Paragraph, Rng As Range
For Each Para In ActiveDocument.Paragraphs
With Para
If .Style = "3 Species" Then
If .Range.ComputeStatistics(wdStatisticWords) > 1 Then
Set Rng = .Range.Words.First
With Rng
Do While .ComputeStatistics(wdStatisticWords) < 2
.MoveEnd wdWord, 1
Loop
.Style = "Bold Italic"
End With
End If
End If
End With
Next
Application.ScreenUpdating = True
End Sub

move parenthesis to comment in local range in Microsoft Word using VBA

I am trying to move all the text I have in parenthesis to a comment in a range I select. I am almost there but for some reason it only works at the start of the range. My macro is as follows:
Sub CommentOutParenthsLocal()
'
' CommentBubble Macro
'
'
Dim myRange As Range
Set myRange = Selection.Range
searchText = "\(*\)"
With myRange.Find
.MatchWildcards = True
Do While .Execute(findText:=searchText, Forward:=True) = True
ActiveDocument.Comments.Add myRange, myRange.Text
myRange.Text = ""
Loop
End With
End Sub
Any advice?
Based on your description, you need to limit your code's scope to what you've actually selected, amongst other things. In that case, try:
Sub CommentOutParenthsLocal()
Application.ScreenUpdating = True
Dim myRange As Range
Set myRange = Selection.Range
With Selection.Range
With .Find
.Text = "\(*\)"
.Forward = True
.MatchWildcards = True
.Execute
End With
Do While .Find.Found = True
If .InRange(myRange) = False Then Exit Do
.Comments.Add .Duplicate, .Text
.Text = vbNullString
.Find.Execute
Loop
End With
Application.ScreenUpdating = False
End Sub

VBA - Get the range as Selection

I'm using Range.Find to find a specific string in a document. When I find this string I want to look at the character BEFORE this string. I had an idea to get the range as selection and then use the Selection.MoveLeft = 1 but I really can't find how to get the range as selection. This is the code I have:
Private Function abc() As Boolean
Set rng = ActiveDocument.Range
With rng.Find
.MatchWildcards = True
Do While .Execute(findText:="123456", Forward:=False) = True
MsgBox (rng.Text)
Set Selection = rng 'Set the selection from range
MsgBox (Selection.Text)
Selection.MoveLeft = 1 'Move the selection
MsgBox (Selection.Text)
Loop
End With
abc = True
End Function
Solution
Here is my solution.
Sub testhis()
Set rng = ActiveDocument.Range
With rng.Find
.MatchWildcards = True
Do While .Execute(findText:="123456", Forward:=False) = True
rng.Select
Selection.MoveLeft Unit:=wdCharacter, Count:=2
MsgBox (Selection.Text)
Loop
End With
End Sub
Hope this helps.
Here's a way you can do it without Selecting
Sub abc()
Dim rng As Range
Set rng = ActiveDocument.Range
With rng.Find
.MatchWildcards = True
Do While .Execute(findText:="123456", Forward:=False) = True
MsgBox rng.Text
rng.Move wdCharacter, -2
rng.Expand wdCharacter
MsgBox rng.Text
Loop
End With
End Sub

How to get a list that is immediately after heading 1 in Word VBA?

The following shows pattern of a very long document:
<heading1>
<numberedlist>
<heading2>
<numberedlist>
<heading3>
<numberedlist>
When I use Document.Lists I get all the lists in the document. When Iterate using Document.Paragraphs where Document.Paragraphs(i).Style = "Heading 1" I get all the headings.
But What I want is the List (not paragraph of the list) which is immediately after "Heading 1"
Assuming that your document can look like one on the picture below:
Using this proposed code you would be able to select first list (immediate after heading) and other similar lists located below Heading but not the second (there is additional paragraph between heading and list- for that situation see additional comments inside code).
Sub List_after_Heading()
Dim rngLIST As Range
Set rngLIST = ActiveDocument.Content
With rngLIST.Find
.Style = "Heading 1" '<--change into your Heading name
.Forward = True
.Wrap = wdFindStop
End With
Do
rngLIST.Find.Execute
If rngLIST.Find.Found Then
'I assume that list start in NEXT paragraph, if not, it wouldn't be found
'or you need to change part of line into .Next.Next paragraphs,
'alternatively some looping would be needed here
'we check if paragraph next to Heading contains a list
If rngLIST.Paragraphs(1).Next.Range.ListParagraphs.Count > 0 Then
'we have the list, but it's not easy to select at once
Dim iLIST As List
For Each iLIST In ActiveDocument.Lists
If iLIST.Range.Start = rngLIST.Paragraphs(1).Next.Range.Start Then
'here we have it... selected
iLIST.Range.Select
'or any other of your code here
End If
Next
End If
End If
Loop While rngLIST.Find.Found
End Sub
I use bookmarks to identify the Headings and then simply return the text between them. But I am not sure by what you mean by But What I want is the List (not paragraph of the list)
ScreenShot
Code
Option Explicit
Sub Sample()
Dim MyRange As Range
Selection.HomeKey Unit:=wdStory
On Error Resume Next
ActiveDocument.Bookmarks("MYStartBookMark").Delete
ActiveDocument.Bookmarks("MYEndBookMark").Delete
On Error GoTo 0
'~~> Find Heading 1
With Selection.Find
.ClearFormatting
.Style = ActiveDocument.Styles("Heading 1")
.Text = ""
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindContinue
.Format = True
.Execute
End With
'~~> Move one space to the right
Selection.MoveRight Unit:=wdCharacter, Count:=1
'~~> Insert the start Book mark
With ActiveDocument.Bookmarks
.Add Range:=Selection.Range, Name:="MYStartBookMark"
.DefaultSorting = wdSortByName
.ShowHidden = False
End With
'~~> Find Heading 2
With Selection.Find
.ClearFormatting
.Style = ActiveDocument.Styles("Heading 2")
.Text = ""
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindContinue
.Format = True
.Execute
End With
'~~> Move one space to the left
Selection.MoveLeft Unit:=wdCharacter, Count:=1
'~~> Insert the end Book mark
With ActiveDocument.Bookmarks
.Add Range:=Selection.Range, Name:="MYEndBookMark"
.DefaultSorting = wdSortByName
.ShowHidden = False
End With
'~~> Identify the range between the Start BookMark and End BookMark
Set MyRange = ActiveDocument.Range
MyRange.Start = MyRange.Bookmarks("MYStartBookMark").Range.End
MyRange.End = MyRange.Bookmarks("MYEndBookMark").Range.Start
'~~> This gives you that text
Debug.Print MyRange.Text
'~~> Delete the BookMarks
On Error Resume Next
ActiveDocument.Bookmarks("MYStartBookMark").Delete
ActiveDocument.Bookmarks("MYEndBookMark").Delete
On Error GoTo 0
End Sub
Result
OTHER TESTS
One might say that what if we do not know what the next heading is? Which is a fair point as we can have two more scenarios. Let me cover them together
After Heading 1, we have Heading 3
The last Heading in a document is Heading 1 and after that there are no headings.
MODIFIED CODE
Option Explicit
Sub Sample()
Dim MyRange As Range
Dim MyArray
Dim strOriginal As String, strTemp As String
Dim numDiff As Long, i As Long, NextHd As Long
Dim NoNextHeading As Boolean
Selection.HomeKey Unit:=wdStory
On Error Resume Next
ActiveDocument.Bookmarks("MYStartBookMark").Delete
ActiveDocument.Bookmarks("MYEndBookMark").Delete
On Error GoTo 0
'~~> Get all the headings in the array
NoNextHeading = True
For i = LBound(MyArray) To UBound(MyArray)
strOriginal = RTrim$(MyArray(i))
strTemp = LTrim$(strOriginal)
numDiff = Len(strOriginal) - Len(strTemp)
numDiff = (numDiff / 2) + 1
'~~> If heading one is found and it is not the last heading
'~~> in the array then find what is the next heading
If numDiff = 1 And i <> UBound(MyArray) Then
strOriginal = RTrim$(MyArray(i + 1))
strTemp = LTrim$(strOriginal)
numDiff = Len(strOriginal) - Len(strTemp)
numDiff = (numDiff / 2) + 1
NextHd = numDiff
NoNextHeading = False
Exit For
End If
Next i
'~~> Find Heading 1
With Selection.Find
.ClearFormatting
.Style = ActiveDocument.Styles("Heading 1")
.Text = ""
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindContinue
.Format = True
.Execute
End With
'~~> Move one space to the right
Selection.MoveRight Unit:=wdCharacter, Count:=1
'~~> Insert the start Book mark
With ActiveDocument.Bookmarks
.Add Range:=Selection.Range, Name:="MYStartBookMark"
.DefaultSorting = wdSortByName
.ShowHidden = False
End With
If NoNextHeading = False Then
'~~> Find Heading NextHd
With Selection.Find
.ClearFormatting
.Style = ActiveDocument.Styles("Heading " & NextHd)
.Text = ""
.Replacement.Text = ""
.Forward = True
.Wrap = wdFindContinue
.Format = True
.Execute
End With
'~~> Move one space to the left
Selection.MoveLeft Unit:=wdCharacter, Count:=1
Else
'~~> Move to the end of the document
ActiveDocument.Characters.Last.Select
Selection.Collapse
End If
'~~> Insert the end Book mark
With ActiveDocument.Bookmarks
.Add Range:=Selection.Range, Name:="MYEndBookMark"
.DefaultSorting = wdSortByName
.ShowHidden = False
End With
'~~> Identify the range between the Start Book Mark and End BookMark
Set MyRange = ActiveDocument.Range
MyRange.Start = MyRange.Bookmarks("MYStartBookMark").Range.End
MyRange.End = MyRange.Bookmarks("MYEndBookMark").Range.Start
'~~> This give you that text
Debug.Print MyRange.Text
'~~> Delete the BookMarks
On Error Resume Next
ActiveDocument.Bookmarks("MYStartBookMark").Delete
ActiveDocument.Bookmarks("MYEndBookMark").Delete
On Error GoTo 0
End Sub