VBA WORD: найти абзац с указанным стилем c - PullRequest
0 голосов
/ 14 апреля 2020

Я пытаюсь написать код на VBA, где я получу номер абзаца, который будет иметь определенный стиль c (скажем, заголовок 1). Я прошёл через al oop и, к сожалению, получаю такую ​​ошибку:

"Object variable or With block variable not set"

Вот мой код:

Public Function FindParagraph(ByVal pStyle As String) As Integer
    Dim doc As Document
    Dim pNum As Integer
    Set doc = ActiveDocument

    For pNum = 1 To doc.Paragraphs.Count
        Debug.Print pNum, doc.Paragraphs(pNum).Range.Style
        If doc.Paragraphs(pNum).Range.Style = pStyle Then
            FindParagraph = pNum
            Exit For
        End If
    Next pNum
End Function

Sub DoSth()
    Dim i As Integer
    i = FindParagraph("Heading 1")
    Debug.Print i
End Sub

Отладчик показывает, что проблема в этой строке: pStyle = doc.Paragraphs(i).Range.Style И на самом деле я смотрю на свой документ Word, и это первая строка оглавления. Вы знаете, почему это так?

Ответы [ 3 ]

1 голос
/ 14 апреля 2020

Код, который вы указали, не компилируется. Выдает ошибку на

While Not (IsEmpty(pStyle))

, потому что метод IsEmpty должен использоваться только для типа Variant, а тип, назначенный для pStyle, является String. Чтобы достичь своих целей, вам нужно изменить эту строку на

While Not pStyle = vbNullString

Обновлен для предоставления исправленной функции

Sub TestFindParagraph()

    Dim IsFound As Boolean
    IsFound = FindParagraph(ActiveDocument.StoryRanges(wdMainTextStory), "Heading 1")

End Sub


Public Function FindParagraph(ByVal SearchRange As Word.Range, ByVal ParaStyle As String) As Long

    Dim ParaIndex As Long
    For ParaIndex = 1 To SearchRange.Paragraphs.Count

        If doc.Paragraphs(ParaIndex).Range.Style = ParaStyle Then

            FindParagraph = ParaIndex
            Exit Function

        End If

    Next

End Function

Обновление 2020-апрель-15 Восстановление TO C Проблема

Код, отправленный ФП и мной самим, не работает, когда абзац является полем Оглавления. Эта ошибка возникает из-за функции элемента по умолчанию для объектов VBA.

Элементом по умолчанию для объекта является метод, который вызывается, если экземпляр объекта задан без квалифицирующего метода. Эта функция может быть полезна, поскольку она упрощает код, но может привести к странным ошибкам, похожим на те, которые мы испытываем.

В Word стили - это объекты с многочисленными свойствами и методами. Метод стиля по умолчанию - NameLocal (см. Браузер объектов для Word.Style), который возвращает Variant, содержащий строку (см. Тип для стиля в locals windows). Следовательно, даже если pStyle определен как тип String, приведение VBA позволяет назначить вариант / строку для String pStyle, и все выглядит нормально.

Однако в случае поля TO C выясняется, что Word не возвращает стиль, заключающий в себе поле TO C, вместо этого он возвращает значение 'nothing', т. Е. Нет стиля для ТО C. Ничто (не то же самое, что vbNullString) не может быть присвоено строке, и, следовательно, возникает ошибка.

Похоже, есть два решения для проблемы, с которой вы столкнулись выше.

  1. Измените код, чтобы использовать правильный синтаксис для необходимой нам информации. то есть Style.NameLocal. К сожалению, это решение также не будет выполнено, потому что мы не можем вызвать метод (NameLocal) для объекта, который является ничем.

  2. Измените тип переменной для pStyle со String на Variant. Типы вариантов могут содержать объекты и, следовательно, могут содержать значение ничто, которое генерируется, когда абзац является полем TO C.

Решение 2, как представляется, будет работать нормально, однако из пуриста В перспективе у вас будет промежуточная переменная варианта, которая захватывает результат из Style и затем проверяет вариант на пустое значение, прежде чем присваивать строковому значению или vbNullString значение pStyle.

Окончательное обновление 2020-апр-15

К сожалению, миссис Ф. отозвала меня на несколько срочных заданий, поэтому забыла добавить этот последний кусочек.

Ловушки для членов по умолчанию можно легко избежать. Это связано с удивительной работой, проделанной людьми в Rubberduck.

http://rubberduckvba.com/

Надстройка Rubberduck для VBA (которая бесплатна) имеет, как один из его многих талантов, гораздо более строгий анализ кода (проверки кода) VBA. Одной из проверок является предупреждение о том, где в коде был использован элемент по умолчанию. Rubberduck действительно устраняет значительную боль при написании кода на VBA, поскольку помогает вам точно понять предположения, которые вы сделали в своем коде (о которых вы даже не подозревали) ...

0 голосов
/ 15 апреля 2020

Вместо for i=1 to ....Count попробуйте for each l oop для лучшей эффективности

Private Sub StylesCount()
    Dim p As Paragraph
    Dim story As Range
    Dim counter As Long

    For Each story In ActiveDocument.StoryRanges
        For Each p In story.Paragraphs
            If StrComp(p.Style, "Heading 1", vbTextCompare) = 0 Then
                counter = counter + 1
            End If
        Next p
    Next story

    Debug.Print counter

End Sub

Работает для стилей абзацев. Для стилей символов вы должны использовать метод .find.

0 голосов
/ 15 апреля 2020

Невозможно, чтобы у абзаца в Word не было стиля абзаца, поэтому проверка на отсутствие у абзаца какого-либо стиля вообще бессмысленна.

Кроме того, циклический просмотр всех абзацев гораздо менее эффективен, чем используя Find. Например, следующий код извлекает индекс абзаца № каждого заголовка 1:

Sub Demo()
Application.ScreenUpdating = False
Dim Rng As Range, i As Long
With ActiveDocument.Range
  Set Rng = .Duplicate
  With .Find
    .ClearFormatting
    .Replacement.ClearFormatting
    .Text = ""
    .Replacement.Text = ""
    .Style = wdStyleHeading1
    .Format = True
    .Forward = True
    .Wrap = wdFindStop
    .MatchWildcards = False
    .Execute
  End With
  Do While .Find.Found
    i = i + 1
    Rng.End = .Duplicate.End
    MsgBox Rng.Paragraphs.Count
    'The next If ... End If block is only needed if the Found content might be in a table
    If .Information(wdWithInTable) = True Then
      If .End = .Cells(1).Range.End - 1 Then
        .End = .Cells(1).Range.End
        .Collapse wdCollapseEnd
        If .Information(wdAtEndOfRowMarker) = True Then
          .End = .End + 1
        End If
      End If
    End If
    'The next line is only needed if the Found content might include the document's final paragraph break
    If .End = ActiveDocument.Range.End Then Exit Do
    .Collapse wdCollapseEnd
    .Find.Execute
  Loop
End With
Application.ScreenUpdating = True
MsgBox i & " instances found."
End Sub

Больше кода, но гораздо быстрее.

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