I’m trying to capitalize the first letter of each word in a document and leave the rest of the word in camelCase.
So as an example:
wordExample
becomes
WordExample
I’ve tried many different variations of the following code (this is the simplest one), but every one of them crashes my MS Word instance on my Mac. I'm running Word 16.87 and macOS is 14.5 Any help will be greatly appreciated. Thanks in advance. - CES
Sub CapitalizeFirstLetterOnly()
Dim doc As Document
Dim word As Range
Dim firstLetter As String
Dim restOfWord As String
Set doc = ActiveDocument
For Each word In doc.words
firstLetter = UCase(Left(word.Text, 1))
restOfWord = Mid(word.Text, 2)
word.Text = firstLetter & restOfWord
Next word
End Sub
I ran this on Word 16.87 on MacOS 14.5 on an M1 Mac mini.
The first point is that altering something in a collection you are iterating via "For Each" can cause an infinite loop, which is what is happening here (a single word can hang Word).
One traditional solution to this is to iterate backwards, but because there is no For Each Backwards..Next loop (if only!) you have to do something more like
Dim word As Long
For word = doc.Words.Count to 1 Step -1
' process doc.Words(word)
Next
There are other things you can do to speed things up or avoid problems, e.g. put a DoEvents statement in your loop (maybe only run it every few hundred/thousand iterations) turn off ScreenUpdating during processing ... and doubtless others.
But as far as I can tell, the main problem here is that accessing the Words collection is painfully slow. It's not just a Mac thing - it's even worse on my Windows box. Further, accessing words nearer the end of the document is much slower than accessing them the beginning. e.g., it took 90 seconds here to process around 5000 words. If you do a single-letter Find/Replace, on the same text, it's almost instantaneous. (So a sequence of find/replace operations might be one way to go).
There is a Question in this general area here with an answer that may be useful, and there may be others. But IMO if your Words are grouped into paragraphs, processing will likely be far faster if you process paragraphs, then words within paragraphs.
e.g. for testing I ended up using this:
Sub CapitalizeFirstLetterOnly()
Dim doc As Document
Dim para As Long
Dim word As Long ' note type change from Word
Dim firstLetter As String
Dim restOfWord As String
Dim st As Date
st = Time ' remember the start time
Set doc = ActiveDocument
On Error GoTo finish
Application.ScreenUpdating = False
For para = doc.Paragraphs.Count To 1 Step -1
With doc.Paragraphs(para).Range.Words
For word = .Count To 1 Step -1
firstLetter = UCase(Left(.Item(word).Text, 1))
restOfWord = Mid(.Item(word).Text, 2)
.Item(word).Text = firstLetter & restOfWord
If (para Mod 20) = 0 Then
Debug.Print para
DoEvents
End If
Next word
End With
Next
finish:
Application.ScreenUpdating = True
Set doc = Nothing ' don't forget this!
Debug.Print st, Time
End Sub