PDA

View Full Version : Solved: find text and change format of containing sentence



dellphinus
10-31-2008, 10:19 AM
Greetings,

New to VBA, some experience with Excel, none with word. Not sure what to search for, but I am looking through old posts- thought I'd just ask while doing so.

I need to search through a document for every occurance of a charcater string, and then change the color and set bold for the sentence, or alternatively, up to the next carriage return, of the contaianing line/sentence.

I've found examples of using find, but can't seem to come up with how to get it to continue for the entire document.

Any help appreciated...

fumei
10-31-2008, 10:47 AM
Let's see if I understand. You are:

1. searching for a specific string - say, "yadda"
2. if found, the sentence containing "yadda" - not just "yadda" itself - should have its font color changed, and bolded.

Correct?

If this is correct, I want to be clear that the attached demo changes the sentence, NOT the paragraph. There is a VERY big difference between a sentence and a paragraph.

Just to (perhaps) help, I made the code toggle between bolded/colored and back again. You execute it by clicking "Demo Changes" on the top toolbar. Here is the code.

Sub ChangeStuff()
Dim r As Range
Set r = ActiveDocument.Range
With r.Find
Do While .Execute(Findtext:="yadda", _
Forward:=True) = True
With r
.Expand Unit:=wdSentence
' logic added to make toggle
' between character styles
If .Style = "BoldColor" Then
.Style = "NotBoldColor"
Else
.Style = "BoldColor"
End If
.Collapse Direction:=wdCollapseEnd
End With
Loop
End With
End Sub

Note that this uses Styles - Character styles - to do the work. So there is a Character style "BoldColor" that makes the characters...ummmm, bold and colored. And a Character style "NotBoldColor" that makes the characters...ummm, not bolded and colored.

Obviously, if you do not have the need to toggle, then the logic that is used to toggle is not required. In that case, the Do loop would simply be:

Do While .Execute(Findtext:="yadda", _
Forward:=True) = True
With r
.Expand Unit:=wdSentence
.Style = "BoldColor"
.Collapse Direction:=wdCollapseEnd
End With
Loop


I strongly recommend that you use Styles. It makes this kind of stuff MUCH, MUCH, easier to do. This demo took me about five minutes to put together.

dellphinus
10-31-2008, 11:10 AM
Outstanding!
But now I have to go figure out what all these new methods and properties are, and how they work, etc. There goes the weekend...

Expanding on this, rather than the do while relying on finding the string, is it possible to loop through all the sentences, and then use a case statement to apply different formatting based on one of several strings in the sentence? Not looking for a sample, just the loop...

E.G.
For each something in r
case instr(1, something, "yadda")
case instr(1, something, "yippe")
case instr(1, something, "yahooee")
Next something
edit: didn't wrap... wrapping necessary or preferred for pseudo-code?
edit 2: hmmm, munged up the case pretty badly... case wouldn't work for this. Have to use multiple IFs...
edit 3: Might not be the most efficient, but multiple "do while" loops inside the with r.find seems to get the job done.

fumei
10-31-2008, 11:38 AM
Yes.

But be careful. You can not use code like:

For Each something In r

There is no Sentence object. Sentences are Ranges. Therefore you have to work with that. But yes, it is possible to test against the string of each sentence.

dellphinus
10-31-2008, 12:09 PM
So, the basic concept is to find the search term (which will be selected) expand the selection, perform the action, collapse the selection, and move on. This is STARTING to make sense. In the sample you provided, I duplicated the Do While loops, and set it up to search for several different strings. Didn't work, only performed first search. Duplicated the with r.find; still only performed first search. Duplicated the set r = activedocument.range, and all was well.


Set r = ActiveDocument.Range
With r.Find
Do While .Execute(Findtext:="www", Forward:=True) = True
With r
.Expand Unit:=wdSentence
.Style = "BoldColor1"
.Collapse Direction:=wdCollapseEnd
End With
Loop
End With

Set r = ActiveDocument.Range
With r.Find
Do While .Execute(Findtext:="xxx", Forward:=True) = True
With r
.Expand Unit:=wdSentence
.Style = "BoldColor2"
.Collapse Direction:=wdCollapseEnd
End With
Loop
End With

Set r = ActiveDocument.Range
With r.Find
Do While .Execute(Findtext:="yyy", Forward:=True) = True
With r
.Expand Unit:=wdSentence
.Style = "BoldColor3"
.Collapse Direction:=wdCollapseEnd
End With
Loop
End With
End Sub

fumei
10-31-2008, 01:11 PM
"Duplicated the set r = activedocument.range,"

Correct. To start a full search again you must re-size the range object to the full document. However, there is a better way, using an array. Using your "www", "xxx", "yyy" example, each of those items are associated with different styles: BoldColor1, BoldColor2, BoldColor3, Right. So make them arrays, like this.

Sub Blah()
Dim Strings()
Dim StyleChange()
Dim r As Range
Dim j As Long

Set r = ActiveDocument.Range
' load the string array
Strings = Array("www", "xxx", _
"yyy")

' load the styles array
StyleChange = Array("BoldColor1", _
"BoldColor2", "BoldColor3")

' Note that the two arrays MATCH in number!

For j = 0 To Ubound(Strings())
With r.Find
Do While .Execute(Findtext:=Strings(j), _
Forward:=True) = True
With r
.Expand Unit:=wdSentence
.Style = StyleChange(j)
.Collapse Direction:=wdCollapseEnd
End With
Loop
End With
' here is where you re-size the Range
' back to the full document
' for the NEXT j
Set r = ActiveDocument.Range
Next j
End Sub

I hope you follow this.

j runs from 0 to Ubound(Strings()) - in this case 3 times (0, 1, 2).

So when:

j = 0, Strings(j) = "www", StyleChanges(j) = "BoldColor1"
j = 1, Strings(j) = "xxx", StyleChanges(j) = "BoldColor2"
j = 2, Strings(j) = "yyy", StyleChanges(j) = "BoldColor3"

The arrays being 0-based.

fumei
10-31-2008, 01:25 PM
As an aside - and until you are VERY comfortable with syntax and constants, I would recommend using the more readable text syntax - these are equivalent.

r.Collapse Direction:=wdCollapseEnd
r.Collapse 0

To VBA, they are precisely the same instruction.
Same as:

r.Collapse Direction:=wdCollapseStart
r.Collapse 1

To find constants, use the ObjectBrowser in the VBE. In my own code, I use constants a great deal, but use the longer text syntax when posting here. If you DO end up using more constants, I encourage you to add more comments, as readability of code is very very important.

' collapse to range end
r.Collapse 0

dellphinus
11-01-2008, 06:24 AM
Fumei, thanks so much for the help. I just went through a similar effort with VBA and Excel... off to Amazon for books... This is happening at the right time of the year though- the long winter evenings will go a little faster now. Thanks again!