Я пытаюсь сделать первую букву каждого слова в документе заглавной, а остальную часть слова оставить в верблюжьем регистре.
Итак, в качестве примера:
словоПример
становится
WordExample
Я пробовал много разных вариантов следующего кода (это самый простой), но каждый из них приводит к сбою моего экземпляра MS Word на моем Mac. Я использую Word 16.87, а macOS — 14.5. Любая помощь будет принята с благодарностью. Заранее спасибо. - КЕС
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
Во-первых, избегайте использования Word
в качестве имени переменной.
а затем вместо изменения текста используйте свойство .Case
.
For Each w In ActiveDocument.Words
w.Case = wdTitleWord
Next
Я думаю, что он выходит из строя, потому что вы изменяете текстовое содержимое, которое он пытается пройти, а это никогда не является хорошей идеей.
Note: It does not matter if you are using a Mac or a PC
Я запустил это в Word 16.87 на MacOS 14.5 на Mac mini M1.
Первый момент заключается в том, что изменение чего-либо в коллекции, которую вы повторяете с помощью «Для каждого», может вызвать бесконечный цикл, что и происходит здесь (одно слово может зависнуть Word).
Одним из традиционных решений этой проблемы является повторение в обратном направлении, но поскольку нет цикла For Each Backwards..Next (если только!), вам придется сделать что-то вроде
Dim word As Long
For word = doc.Words.Count to 1 Step -1
' process doc.Words(word)
Next
Есть и другие вещи, которые вы можете сделать, чтобы ускорить процесс или избежать проблем, например. поместите оператор DoEvents в свой цикл (возможно, запускайте его только каждые несколько сотен/тысяч итераций) отключить ScreenUpdating во время обработки ... и, несомненно, другие.
Но, насколько я могу судить, основная проблема здесь в том, что доступ к коллекции Words происходит очень медленно. Это касается не только Mac — на моем компьютере с Windows дела обстоят еще хуже. Кроме того, доступ к словам ближе к концу документа происходит намного медленнее, чем доступ к ним в начале. например, здесь потребовалось 90 секунд, чтобы обработать около 5000 слов. Если вы выполните поиск/замену одной буквы в одном и том же тексте, это произойдет почти мгновенно. (Поэтому последовательность операций поиска/замены может быть одним из способов).
В этой общей области есть Вопрос здесь с ответом, который может быть полезен, а могут быть и другие. Но, по моему мнению, если ваши слова сгруппированы в абзацы, обработка, вероятно, будет намного быстрее, если вы обрабатываете абзацы, а затем слова внутри абзацев.
например для тестирования я использовал это:
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
Он уже доступен, макрос не нужен:
С вашим кодом есть две проблемы.
Первое, как также упоминает braX, заключается в том, что вы никогда не должны присваивать переменной то же имя, что и объекту, например. слово, абзац, таблица и т. д.
Во-вторых, ваш код заменяет все слово, что портит набор слов, которые вы просматриваете. В этом случае вы можете избежать необходимости обратного цикла, просто изменив первый символ напрямую.
Sub CapitalizeFirstLetterOnly()
Dim doc As Document
Dim wd As Range
Set doc = ActiveDocument
For Each wd In doc.Words
With wd.Characters.First
.Text = UCase(.Text)
End With
Next wd
End Sub
Примечание. У меня нет доступа к Mac, чтобы проверить это, но на ПК он работает нормально.
Йонссон, спасибо за советы...