Checking case of first two letters of each word

C

cyraxote

I am trying to write a macro to search through a reference list, find
the titles, and make each word (after the first) lower case, UNLESS
(1) the word is already lower case or (2) both the first and the
second letters are upper case, indicating an acronym.

I can find the titles with no problem, but testing each word is really
stumping me. Below is the latest version of this code:

For wd = 1 To Selection.Words.Count
MyWord = Selection.Words(wd)
If MyWord.Characters(1) = wdUpperCase Then
L1 = True
Else
L1 = False
End If
If MyWord.Characters(2) = wdUpperCase Then
L2 = True
Else
L2 = False
End If
If L1 = True And L2 = False Then
MyWord.Case = wdLowerCase
End If
Next wd

The problem is that word just gives up execution on the line "If
MyWord.Characters(1) = wdUpperCase Then"--as I step through, the
yellow highlight disappears at this line, and a blinking cursor
appears in the margin. Stepping to the next line moves the yellow
highlight back to the beginning of the macro.

Now, I'm pretty sure that I'm mixing my object methods and/or
properties here in some way. I have a fairly good grasp of the
Selection object, but the Range object is like a foreign country.

Any help would be greatly appreciated.

Thanks.

Rodney
 
J

Jay Freedman

Right, you're mixing things up. MyWord.Characters(1) is a character,
such as 'A' or 'a'. In contrast, wdUpperCase is a constant with the
value 1. That makes the If statement as written completely
meaningless, since you'll never find the character with the ASCII
value 1 in any Word document.

The statement you should use is

If MyWord.Characters(1) = UCase(MyWord.Characters(1)) Then

and similarly for MyWord.Characters(2). The UCase function returns the
upper-case equivalent if the input is lower-case, or the character
itself if the input is upper-case or non-alphabetic.

Assigning the wdLowerCase constant to MyWord.Case is valid, because
they're the same type.

Besides these changes, there are other problems that should have
prevented the macro from getting even as far as you described. You
must declare

Dim MyWord As Range

and use the Set keyword at the beginning of the line that assigns
Selection.Words(wd) to it. If I don't do that, I get an "Object
required" error when the macro tries to access MyWord.Characters(1).

Because Word considers punctuation to be a Word object, you'll get
another error on the first punctuation because MyWord.Characters(2)
doesn't exist. To fix that, change the second test to

If Len(myWord) > 1 Then
If myWord.Characters(2) = UCase(myWord.Characters(2)) Then
L2 = True
Else
L2 = False
End If
Else
L2 = False
End If

--
Regards,
Jay Freedman
Microsoft Word MVP
Email cannot be acknowledged; please post all follow-ups to the
newsgroup so all may benefit.
 
J

Jonathan West

Jay Freedman said:
Right, you're mixing things up. MyWord.Characters(1) is a character,
such as 'A' or 'a'. In contrast, wdUpperCase is a constant with the
value 1. That makes the If statement as written completely
meaningless, since you'll never find the character with the ASCII
value 1 in any Word document.

The statement you should use is

If MyWord.Characters(1) = UCase(MyWord.Characters(1)) Then

Not quite. That would return true for any non-alphabetic characters as well.
Try this instead.

If MyWord.Characters(1) Like "[A-Z]" Then
 
C

cyraxote

Jay, Jonathan:

Very helpful, as usual. Your suggestions and additions worked like a
charm.

I also made a few further changes:

- I skipped the first word by changing the start of the counter,
- I added a test to skip one-letter words.

I tried to add a test to skip italic words, but It doesn't seem to
work:

For Wd = 2 To Selection.Words.Count
Set MyWord = Selection.Words(Wd)
If Selection.Font.Italic = True Then
GoTo Jumpout:
End If
If Len(MyWord) > 1 Then
If MyWord.Characters(1) Like "[A-Z]" Then
L1 = True
Else
L1 = False
End If
Else
L1 = False
End If
If Len(MyWord) > 1 Then
If MyWord.Characters(2) Like "[A-Z]" Then
L2 = True
Else
L2 = False
End If
Else
L2 = False
End If
If L1 = True And L2 = False Then
MyWord.Case = wdLowerCase
MyWord.HighlightColorIndex = wdBrightGreen
End If
Jumpout:
Next Wd

When I hover my cursor over "Selection.Font.Italic" in the code window
during execution, the tooltip says "Selection.Font.Italic = 9999999"
whether the word is italic or not, and when I hover it over "True" in
the same line, the tooltip says "True=True." I seem to recall
somewhere in brain that 9999999 means that the selection is a mixed
type...? Which leads me to believe that I'm checking whether the
entire selection is italic rather than the current word...?

Thanks again for all your help.

Rodney
 
J

Jay Freedman

Your analysis is correct: the statement 'If Selection.Font.Italic =
True Then' tests whether the entire Selection is italic, but the
expression Selection.Font.Italic will have the value 9999999 (which is
the value of the built-in constant wdUndefined) when part of the
Selection is italic and part isn't. The statement should be

If MyWord.Font.Italic = True Then

By the way, I'd strongly urge you to declare all your variables, as
explained in
http://www.word.mvps.org/FAQs/MacrosVBA/DeclareVariables.htm
(unfortunately, that site is down at the moment but should return
soon). For this macro, they should be

Dim MyWord As Range
Dim Wd As Long
Dim L1 As Boolean, L2 As Boolean

And to force yourself to remember to do this, put the statement

Option Explicit

at the top of each module. If you go into Tools > Options in the VBA
editor and check the box for "Require Variable Declaration", that
statement will be included automatically each time you create a
module.

--
Regards,
Jay Freedman
Microsoft Word MVP
Email cannot be acknowledged; please post all follow-ups to the
newsgroup so all may benefit.
 
C

cyraxote

Jay:

They're all declared. I just didn't copy that part of the code.

Thanks again.

Rodney
 
C

cyraxote

OK, one last puzzle.

In the following title:

Glomerular-Specific Alterations of VEGF-A Expression Lead to Distinct
Congenital and Acquired Renal Diseases

the macro correctly makes everything lower case except the A:

Glomerular-specific alterations of VEGF-a expression lead to distinct
congenital and acquired renal diseases.

The A after "VEGF" should remain capped. Other references with single
capped letters (e.g., "anti-E-selectin" or just "E-selectin") are left
alone, as they should be.

Does Word include the space after A as part of the the "word" A?

If so, would this stand up to a test of the "second character" in the
"word", e.g.,

If MyWord.Characters(2) Like " " Then

or

If MyWord.Characters(2) = Chr(32) Then

Or am I again mixing apples and kumquats?

Thanks.

Rodney
 
C

cyraxote

One last puzzle:

The macro changes this title:

Glomerular-Specific Alterations of VEGF-A Expression Lead to Distinct
Congenital and Acquired Renal Diseases

to this:

Glomerular-specific alterations of VEGF-a expression lead to distinct
congenital and acquired renal diseases

which is correct except for the "A" after "VEGF". This doesn't happen
with other single letters, such as "anti-E-selectin" or just "E-
selectin," which leads me to believe that Word is including the
trailing space in the "word" (i.e., "A" is really "A ").

Would something like the following find this?

If MyWord.Characters(2) Like " " Then

or

If MyWord.Characters(2) = Chr(32) Then

Thanks.

Rodney
 
D

Doug Robbins - Word MVP

The following handles that case correctly

Dim drange As Range
Selection.HomeKey wdStory
Selection.Find.ClearFormatting
With Selection.Find
Do While .Execute(findText:="([!^13])([A-Z]{1})([a-z]{1,})",
MatchWildcards:=True, Wrap:=wdFindContinue, Forward:=True) = True
Set drange = Selection.Range
drange.Start = drange.Start + 1
drange.End = drange.Start + 1
drange.Text = LCase(drange.Text)
Loop
End With


--
Hope this helps.

Please reply to the newsgroup unless you wish to avail yourself of my
services on a paid consulting basis.

Doug Robbins - Word MVP
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top