# Word VBA "for each" statement



## bruderbell (Sep 21, 2009)

Hi all,
I'm trying to code a little macro to check each word of a document to see if the first 2 characters are capitals, and then perform a function if so.  I think I want to use a for each statement, but I can't figure out how to do so exactly.

dim x as (word, but it won't let me use this since word is defined as the application and not an object type)
for each x in words
if first letter is caps and second letter is caps
then
do my code
end if
next
end sub

Can anyone help me fill in the gaps?


----------



## schielrn (Sep 21, 2009)

Are you doing this in microsoft word? And are you wanting to check EVERY SINGLE word within that document?  Maybe try something like:


```
Sub test()
For Each w In ThisDocument.Words
If Left(w, 2) = UCase(Left(w, 2)) Then
    
Else
    MsgBox w & " is not capitalized"
End If
Next w
End Sub
```
Right now all this does is gives a message box with the word not capitalized for the first 2 letters.


----------



## Macropod (Sep 22, 2009)

Hi bruderbell,

You can find words beginning with two caps using Word's Find/Replace:

```
Sub Find2Caps()
  With Selection.Find
    .ClearFormatting
    .Text = "<[A-Z]{2}"
    .Forward = True
    .Wrap = wdFindContinue
    .Format = False
    .MatchCase = False
    .MatchWholeWord = False
    .MatchAllWordForms = False
    .MatchSoundsLike = False
    .MatchWildcards = True
    .Find.Execute
  End With
End Sub
```
With more detail of what you want to do, it would be possible to turn this into something more useful.


----------



## bruderbell (Sep 22, 2009)

Thanks for the replies folks.  My goal is to automate the creation of an acronym list for a document.  Hence the effort to find any words with 2 caps at the start.  
I tried got something useful with the following:

Sub test()
Dim ate As String
doc1 = ActiveDocument
doc2 = Documents.Add
For Each w In Documents(doc1).Words
If IsNumeric(Left(w, 1)) Then GoTo a
If Left(w, 2) = UCase(Left(w, 2)) And Left(w, 1) <> " " And _
    w <> Chr(182) And Left(w, 1) <> Chr(46) And Left(w, 1) <> "_" _
    And Left(w, 1) <> "(" And Left(w, 1) <> ")" And Len(w) > 1 _
    And Left(w, 1) <> "," And Left(w, 2) <> "??" And Left(w, 1) <> Chr(7) _
    And Left(w, 1) <> "-" And Left(w, 2) <> UCase(Left(w, 1)) & " " _
    And Left(w, 1) <> Chr(149) Then
Documents(doc2).Activate
Selection.TypeText (w)
Selection.TypeParagraph
End If
a:
Next w
End Sub

I noted that schielrn's method returns quite a bit of stuff (two punctuations in a row, spaces, etc) so I put in a ton of ANDs.  I haven't tried your method yet, macropod.  I eventually want to have all the acronyms populate an excel spreadsheet, then sort alphabetically, remove duplicates.  I can work those parts out.  
My next question is this: can a macro be worked up that will check the first letters of word and return any collection of words starting with the acronym?  So if the first part of the macro finds the acronym BFM and the phrase "big fat macro" is in the document, I'd like to return that phrase.  Ideas?


----------



## Macropod (Sep 22, 2009)

Hi bruderbell,

Either macro could be developed into something that could create an array of acronyms plus their meanings, but the problem you'd need to overcome is having a reliable way for the macro to determine where each acronym's expansion begins and ends. For example, 'MA' might mean 'Master of Arts', while 'TLA' means 'Three-Letter Acronym', 'PA' means 'Public Address' and 'CO2' is 'Carbon Dioxide'. In other words, there isn't necessarily any correspondence between the number of characters in the acronym and the number of words in the corresponding expression.


----------



## bruderbell (Sep 23, 2009)

Macropod - is there a way for me to use something similar to your notation in my macro?  I've shyed away from teh find method because it only finds the first instance.  After it finds that instance I would expand to select the whole word, then copy paste it into my second document, and then go back to finding.  From my experiments I end up needing to then find twice to get the second instance, three to get the third, and so on.  That makes the running time of the macro really long.

So is there a way to say something like 

If Left(w, 2) Like "[A-Z]{2}" Then

or something to that effect?


----------



## Macropod (Sep 23, 2009)

Hi bruderbell,

A macro using the Find method doesn't have to stop at the first instance. The only reason the one I posted does so is that it doesn't have any code to tell it what to do next - it was, after all, just a demo of how 'Find' can be used to locate a word starting with two capitals. In practice, I expect such a macro would run much faster than one such as schielrn posted, simply because using Word's native functions is faster than a vba equivalent. Give this a try:
	
	
	
	
	
	



```
Sub ListAcronyms()
Dim i As Integer, StrList As String
With Selection.Find
  .ClearFormatting
  .Text = "<[A-Z]{2,}"
  .Forward = True
  .Wrap = wdFindContinue
  .Format = False
  .MatchCase = False
  .MatchWholeWord = False
  .MatchAllWordForms = False
  .MatchSoundsLike = False
  .MatchWildcards = True
  .Execute
  Do While .Found
    i = i + 1
    StrList = StrList & vbCr & Selection.Text
    Selection.Collapse wdCollapseEnd
    .Execute
  Loop
  MsgBox i & " acronyms found:" & StrList
End With
End Sub
```
Notes:
1. In the previous macro I posted, '.Find.Execute' should have been just '.Execute'
2. The above macro lists all uppercase strings of two or more characters at the beginning of a word. This is accomplished by adding a comma to the Find expression - it could be limited to, say, 2-4 characters by adding a '4' after that comma.


----------

