Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations biv343 on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Want to use VBA to search by style and change case 3

Status
Not open for further replies.

sophisticatedpenguin

Technical User
Oct 12, 2005
31
GB
Hi,

I have a Word document in which the text is styled. I want to search for the text in one particular style ("Puzzle Title"), which is at present all in upper case, and change it to be in Title Case. It seems like it should be possible but I'm really stuck. I know to use

Code:
Selection.Find.Style = ActiveDocument.Styles("Puzzle Title")

to find the style, and I thought maybe I could use a loop of some kind.

Can anyone help me out with this?

Many thanks,
SP
 




Hi,

Try something like this...
Code:
dim stl as style
for each stl in thisdocument.styles
  with stl
     select case .NameLocal
        case "Puzzle Title"
          'what to do  with this style
     end select
  end with
next
Or maybe loop thru the Paragraphs collection in the document, checking the Style property of that paragraph in the case statement.

Skip,

[glasses] When a diminutive clarvoyant had disappeared from detention, headlines read...
Small Medium at Large[tongue]
 
Rather something like this?
(Gerry will curse me for using Selection again [tongue])
Code:
Sub TitlizeStyles()
Dim wd

Selection.HomeKey unit:=wdStory
With Selection.Find
    .ClearFormatting
    .Text = ""
    .Style = ActiveDocument.Styles("Puzzle Title")
    .Format = True
    .Execute
End With

Do While Selection.Find.Found
    For Each wd In Selection.Range.Words
        wd.Case = wdLowerCase
        wd.Characters(1).Case = wdUpperCase
    Next wd
    Selection.Collapse wdCollapseEnd
    Selection.Find.Execute
Loop

End Sub

[navy]"We had to turn off that service to comply with the CDA Bill."[/navy]
- The Bastard Operator From Hell
 
Thank you both, Skip and MakeItSo. I tried MakeItSo's version and it worked like a dream. I would never have managed to sort that out myself! I was trying to use the Title Case formatting but couldn't get VBA to let me use it with finding and replacing. This is a really neat workaround.

Please could you help me to learn by clarifying a couple of things:

(1) What is this bit for:
Code:
Selection.Collapse wdCollapseEnd

(2) In this bit:
Code:
wd.Characters(1).Case = wdUpperCase
does the (1) just select the first character? I didn't know you could do that!

Many thanks again,
SP
 
Hi SP,

Re 1: The Selection.Find does as its name incurs: it searches within a selection. Once the style is found, the found part is highlighted, i.e. selected. You have to unselect before continuing or you will keep on searching in the selected part forever. Hence this command, which will collaps, i.e. unselect the selction.

re2: Yepp, exactly this. I use it in a CaseChanger macro I have written a while ago and it was the only way I found to create Title Case.

;-)

[navy]"We had to turn off that service to comply with the CDA Bill."[/navy]
- The Bastard Operator From Hell
 
Here it is using a Range...MakeItSo, you knew I was going to do this.
Code:
Sub ChangeStyleCase()
Dim r As Range
Set r = ActiveDocument.Range
With r.Find
   .Style = "Puzzle Title"
   Do While .Execute(Forward:=True) = True
       r.Case = wdTitleWord
   Loop
End With
End Sub

This changes all ranges of "Puzzle Title" to TitleCase, by word.

If you wanted to change it to Titlecase by sentence, use:
Code:
r.Case = wdTitleSentence

No use of Selection, and there is no need to Collapse, as you are changing the attribute of each .Found of the range object itself.

faq219-2884

Gerry
My paintings and sculpture
 
I would like to point out, and only for the purpose of assisting knowledge, that...say you have the text:

THIS IS SOME TEXT.

Say it is the Style "Puzzle Text". Here is MakeItSo's core code snippet:
Code:
Do While Selection.Find.Found
    For Each wd In Selection.Range.Words
        wd.Case = wdLowerCase
        wd.Characters(1).Case = wdUpperCase
    Next wd
    Selection.Collapse wdCollapseEnd
    Selection.Find.Execute

Here is what it actually does, the actual real instructions that are carried out, regarding the example "THIS IS SOME TEXT."

1. finds "THIS IS SOME TEXT."
2. sets the Variant wd as "THIS"
3. sets wd case attribute as LowerCase
4. sets wd 1st character attribute as UpperCase
5. sets the Variant wd as "IS"
6. sets wd case attribute as LowerCase
7. sets wd 1st character attribute as UpperCase
8. sets the Variant wd as "SOME"
9. sets wd case attribute as LowerCase
10. sets wd 1st character attribute as UpperCase
11. sets the Variant wd as "TEXT"
12. sets wd case attribute as LowerCase
13. sets wd 1st character attribute as UpperCase
14. sets the Variant wd as "."
15. sets wd case attribute as LowerCase
16. sets wd 1st character attribute as UpperCase
17. sets the Variant wd as vbCrLf (the paragraph mark)
18. sets wd case attribute as LowerCase
19. sets wd 1st character attribute as UpperCase
20. collapses the Selection
21. goes to the next .Execute of Selection.Find

Yes, the period (".") and the paragraph mark are considered separate and distinct "words", and since the code is:
Code:
[b][COLOR=red]For Each[/color red][/b] wd In Selection.Range.Words
they are indeed processed, each actioned with the instructions that every other "word" is actioned with.

Here is what using a Range actually does, the actual real instructions that are carried out, regarding the example "THIS IS SOME TEXT."

1. finds "THIS IS SOME TEXT."
2. makes it TitleCase (either by word, or by sentence)
3. goes to the next .Execute of the range.Find


Look at the difference. Please, please, please, MakeItSo I am NOT, repeat not, being critical of your code. It works, and that, of course, is the main thing.

However, really understanding how Word "thinks" of things, the object model, makes a huge difference in:

1. writing cleaner, shorter, more efficient code
2. making it easier to debug your code, AND easier for
someone else to figure out what you are doing
3. getting working code up and running quicker, as you are
working with how Word operates
4. understanding how documents are really structured, thus
designing/developing documents that take advantage of
that structure.

faq219-2884

Gerry
My paintings and sculpture
 
Just to put some real numbers to this:

THIS IS SOME TEXT.
THIS IS SOME OTHER TEXT.
THIS IS SOME YADDA YADDA YADDA.

Say the above is the text that has "Puzzle Title" style. Three paragraphs.

Putting a counter on each carried out instruction using the For Each wd, Lowercase, UpperCase, Selection collapse:
Code:
Do While Selection.Find.Found
    For Each wd In Selection.Range.Words
      j = j + 1 [COLOR=red]' one instruction for EACH setting of wd[/color red]
        wd.Case = wdLowerCase
               [COLOR=red]' one instruction for lowercase[/color red]
      j = j + 1
        wd.Characters(1).Case = wdUpperCase
               [COLOR=red]' one instruction for uppercase[/color red]
      j = j + 1
    Next wd
    Selection.Collapse wdCollapseEnd
   [COLOR=red] ' one instruction to collapse[/color red]
    j = j + 1
    Selection.Find.Execute
Loop
MsgBox "Done.  " & j & " instructions carried out."
The message is: "Done. 66 instructions carried out."

Using a range and counter:
Code:
With r.Find
   .Style = "Puzzle Title"
   Do While .Execute(Forward:=True) = True
      ' one instruction for each found
      j = j + 1
       r.Case = wdTitleWord
   Loop
End With
MsgBox "Done.  " & j & " instructions."
The message is: "Done. 3 instructions carried out."

There are 3 ranges with Puzzle Title, so only 3 instructions carried out.

Say the text was:

THIS IS SOME BATHERING SOMETHING TEXT.
THIS IS SOME OTHER WHOHA WHATEVER KIND OF TEXT.
THIS IS SOME YADDA YADDA YADDA.

Using the For Each wd...

"Done. 84 instructions carried out."

Using the range.....it is still:

"Done. 3 instructions carried out."

There are still 3 Ranges, no matter what the text is. So there will still be only 3 instructions.

Using Selection, and a For Each word (including the "." and ^p), the more text there is, the number of carried out instructions goes up.

faq219-2884

Gerry
My paintings and sculpture
 
Hehehehe, of course I knew, Gerry!
I searched for my code, but couldn't find that Title Case.
(Partially of course, because I didn't know this case was called "Title case".
[tongue]

So, many, many thanks for this beautiful piece of code.
I'll immediately adapt my own case-changer code.

[thumbsup]

Cheers,
Andy

[navy]"We had to turn off that service to comply with the CDA Bill."[/navy]
- The Bastard Operator From Hell
 
Okie dokie:

One more thanks to Gerry: using range, one MUST also use the Word constants wdLowerCase etc. instead of vbLowerCase to ensure the correct result.

So now, my own case-changer looks a bit slimmer and if I ever apply it to several pages, surely also measurably faster.
I have made four tool buttons (i.e. 4 macros), with which one can change the case of the entire range selected in Word to either

lower case
Proper case
Title Case or
UPPER CASE

Code:
Sub LowerIt()
ChangeCase "l"
End Sub

Sub UpperIt()
ChangeCase "u"
End Sub

Sub ProperIt()
ChangeCase "p"
End Sub

Sub TitleIt()
ChangeCase "t"
End Sub

Sub ChangeCase(How As String)
Dim r As Range
Set r = Selection.Range

Select Case How
    Case "l"
        r.Case = wdLowerCase
    Case "u"
        r.Case = wdUpperCase
    Case "p"
        r.Case = wdLowerCase
        r.Case = wdTitleSentence
    Case "t"
        r.Case = wdTitleWord
End Select

End Sub

As you can see, the Proper case part looks a bit funny. There is no "Proper case" constant in Word, except for the "TitleSentence". That however will not toggle the case if it was set to TitleWord before. That is why I first set it to lower case and THEN to TileSentence, which will do the trick.
;-)

[navy]"We had to turn off that service to comply with the CDA Bill."[/navy]
- The Bastard Operator From Hell
 
using range, one MUST also use the Word constants wdLowerCase etc. instead of vbLowerCase to ensure the correct result."

Yes indeedy. You can use the constant number though.
Code:
Select Case How
    Case "l"
        r.Case = 0
    Case "u"
        r.Case = 1
    Case "p"
        r.Case = 0
        r.Case = 4
    Case "t"
        r.Case = 2
End Select
See the Object Browser.

I sometimes use numerics, but generally, in the interest of readability, and faster debugging, shrug, words (wdLowercase) are better.

Just for fun, there is a Character constant that is rarely used, wdNextCase. Believe it or not, it will make the case the next case in the list, AND it is circular! You can go on forever. It will go back and start again. However....it does not quite follow the list in Format > Change Case.

Say starting at lowercase, NextCase makes it:

TitleCase

then NextCase makes it UpperCase, then back to lowercase.

Weird huh?

faq219-2884

Gerry
My paintings and sculpture
 
SP, how are you going to get the hang of this?

The same way we ALL did. Doing it, and paying attention.

The biggest factor (in general VBA terms ie. for any VBA compliant application), IMO, is learning to use objects. Getting that into your understanding will make a huge difference.

For Word, specifically, there are two vital objects: Range, and the paragraph mark. And maybe toss in the HeaderFooter object, as headers and footers can drive you batty.

faq219-2884

Gerry
My paintings and sculpture
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top