Макрос MS Word для написания заглавной буквы каждого слова в документе на Mac. Все, что я пытаюсь сделать, приводит к сбою Word

Я пытаюсь сделать первую букву каждого слова в документе заглавной, а остальную часть слова оставить в верблюжьем регистре.

Итак, в качестве примера:

словоПример

становится

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
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
51
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Во-первых, избегайте использования 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

Йонссон, спасибо за советы...

CES 09.08.2024 16:07

Он уже доступен, макрос не нужен:

С вашим кодом есть две проблемы.

Первое, как также упоминает 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, чтобы проверить это, но на ПК он работает нормально.

Другие вопросы по теме