Поиск и замена с VBA для Word перезаписывает предыдущий стиль - PullRequest
0 голосов
/ 06 ноября 2019

Я пишу сценарий VBA для создания документов Word из уже определенного шаблона. В нем мне нужно уметь писать заголовки вместе с телом для каждого заголовка. В качестве небольшого примера у меня есть документ Word, который содержит только <PLACEHOLDER>. Для каждого заголовка и тела, которые мне нужно написать, я использую функцию поиска и замены в VBA, чтобы найти <PLACEHOLDER> и заменить его именем заголовка, новой строкой, а затем <PLACEHOLDER> снова. Это повторяется до тех пор, пока не будет написано имя и тело каждого заголовка, а затем окончательный символ <PLACEHOLDER> заменяется на новую строку.

Замена текста работает нормально, но указанный мной стиль перезаписывается вызовом next для замены. Это приводит к тому, что все, что я только что заменил, имеет стиль, каким бы ни был мой последний вызов моей функции замены.

Код VBA (прогон main)

Option Explicit

Sub replace_stuff(search_string As String, replace_string As String, style As Integer)
    With ActiveDocument.Range.Find
        .Text = search_string
        .Replacement.Text = replace_string
        .Replacement.style = style
        .Forward = True
        .Wrap = wdFindContinue
        .Format = True
        .MatchWholeWord = False
        .MatchSoundsLike = False
        .MatchAllWordForms = False
        .Execute Replace:=wdReplaceAll
    End With
End Sub

Sub main()
    Dim section_names(2) As String
    section_names(0) = "Introduction"
    section_names(1) = "Background"
    section_names(2) = "Conclusion"

    Dim section_bodies(2) As String
    section_bodies(0) = "This is the body text for the introduction! Fetched from some file."
    section_bodies(1) = "And Background... I have no issue fetching data from the files."
    section_bodies(2) = "And for the conclusion... But I want the styles to 'stick'!"

    Dim i As Integer
    For i = 0 To 2
        ' Writes each section name as wsStyleHeading2, and then the section body as wdStyleNormal
        Call replace_stuff("<PLACEHOLDER>", section_names(i) & Chr(11) & "<PLACEHOLDER>", wdStyleHeading2)
        Call replace_stuff("<PLACEHOLDER>", section_bodies(i) & Chr(11) & "<PLACEHOLDER>", wdStyleNormal)
    Next i
    Call replace_stuff("<PLACEHOLDER>", Chr(11), wdStyleNormal)

End Sub

Входной документ: Документ Word, содержащий только <PLACEHOLDER>.

<PLACEHOLDER>

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

expected output

Фактический вывод: Однако, что я на самом деле получаю, это все как wdStyleNormal стиль, подобный следующему:

actual

Я думаю, что проблему можно решить, вставляя разрыв абзаца между каждым переходом стиля , но когда я пытаюсь использовать vbCrLF или Chr(10) & Chr(13) или vbNewLine вместо chr(11), который я использую сейчас, Каждая строка начинается с вопросительного знака в штучной упаковке, например:

enter image description here

Ответы [ 2 ]

1 голос
/ 06 ноября 2019

Обновление из обсуждения в комментариях к другому ответу. Описанная ниже проблема относится к Word 2016 и более ранним версиям. Начиная с Office 365 (и, возможно, Word 2019, но это не подтверждено), поведение Replace было изменено для «преобразования» ANSI 13 в «реальный» знак абзаца,поэтому проблема в вопросе не возникнет.

Ответ

Причиной нечетного поведения при форматировании является использование Chr(11), которое вставляет новую строку (Shift + Enter) вместо нового абзаца. Таким образом, стиль абзаца, примененный к любой части этого текста, форматирует весь текст с тем же стилем.

В этом конкретном случае (работа с Replace), vbCr или эквивалентный Chr(13) также не делают 'не работает, потому что это не настоящий абзац Word. Абзац - это нечто большее, чем просто код 13 ANSI - он содержит информацию о форматировании абзаца. Таким образом, пока код выполняется, Word на самом деле не распознает их как настоящие метки абзаца, и назначение стиля абзаца применяется ко «всему».

Что работает, так это использование строки ^p, котораяв Word Find / Replace это «псевдоним» для полного знака абзаца. Так, например:

replace_stuff "<PLACEHOLDER>", section_names(i) & "^p" & "<PLACEHOLDER>", wdStyleHeading2
replace_stuff "<PLACEHOLDER>", section_bodies(i) & "^p" & "<PLACEHOLDER>", wdStyleNormal

Однако существует более эффективный способ создания документа, чем вставка заполнителя для каждого нового элемента и использование Find / Replace для замены заполнителя содержимым документа. Более традиционный подход - работать с Range объектом (думать о нем, как о невидимом выделении) ...

Назначить содержимое для Range, отформатировать его, свернуть (как нажатие стрелки вправо длявыбор) и повторить. Вот пример, который возвращает тот же результат, что и (исправленный) код в вопросе:

Sub main()
  Dim rng As Range

  Set rng = ActiveDocument.content
  Dim section_names(2) As String
  section_names(0) = "Introduction"
  section_names(1) = "Background"
  section_names(2) = "Conclusion"

  Dim section_bodies(2) As String
  section_bodies(0) = "This is the body text for the introduction! Fetched from some file."
  section_bodies(1) = "And Background... I have no issue fetching data from the files."
  section_bodies(2) = "And for the conclusion... But I want the styles to 'stick'!"

  Dim i As Integer
  For i = 0 To 2
    BuildParagraph section_names(i), wdStyleHeading2, rng
    BuildParagraph section_bodies(i), wdStyleNormal, rng
  Next i
End Sub

Sub BuildParagraph(para_text As String, para_style As Long, rng As Range)
        rng.Text = para_text
        rng.style = para_style
        rng.InsertParagraphAfter
        rng.Collapse wdCollapseEnd
End Sub
0 голосов
/ 06 ноября 2019

Проблема вызвана использованием Chr(11), что означает разрыв строки вручную. Это приводит к тому, что весь текст находится в одном абзаце. Когда применяется стиль абзаца, он применяется ко всему абзацу.

Замените Chr(11) на vbCr, чтобы каждый фрагмент текста находился в отдельном абзаце.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...