На что ссылаются гиперссылки range.start и range.end? - PullRequest
0 голосов
/ 15 октября 2019

Я пытаюсь манипулировать некоторым текстом из документа MS Word, который содержит гиперссылки. Однако я понимаю, что именно возвращают Range.Start и Range.End. Я набросал несколько случайных слов в пустой документ и добавил несколько гиперссылок. Затем записал следующий макрос ...

Sub ExtractHyperlinks()

    Dim rHyperlink As Range
    Dim rEverything As Range
    Dim wdHyperlink As Hyperlink

    For Each wdHyperlink In ActiveDocument.Hyperlinks
        Set rHyperlink = wdHyperlink.Range
        Set rEverything = ActiveDocument.Range
        rEverything.TextRetrievalMode.IncludeFieldCodes = True
        Debug.Print "#" & Mid(rEverything.Text, rHyperlink.Start, rHyperlink.End - rHyperlink.Start) & "#" & vbCrLf
    Next

End Sub

Однако вывод между # не совсем совпадает с гиперссылками и состоит из одного или двух символов. Так что, если .Start и .End не возвращают позиции символов, что они возвращают?

Ответы [ 3 ]

0 голосов
/ 15 октября 2019

Это немного упрощает, но это потому, что rEverything считает все до гиперссылки, затем все символы в поле гиперссылки код (включая 1 символ для каждого открытияи закрывающие фигурные скобки поля), затем все символы в поле гиперссылки результат , затем все символы после поля.

Однако количество символов вдиапазон (например, rEverything.Characters.Count или len (rEverything)) включает в себя только поле результат , если TextRetrievalMode.IncludeFieldCodes имеет значение False и включает только поле code , если TextRetrievalMode.IncludeFieldCodes имеет значениеустановите в True.

Таким образом, количество символов всегда меньше, чем range.End-range.Start.

В этом случае, если вы измените выражение Debug на что-то вроде

    Debug.Print "#" & Mid(rEverything.Text, rHyperlink.Start, rHyperlink.End - rHyperlink.Start - (rEverything.End - rEverything.Start - 1 - Len(rEverything))) & "#" & vbCrLf

вы можете увидеть результаты более точно в соответствии с вашими ожиданиями.

Другой способ визуализации происходящего заключается в следующем:

Создайте очень короткий документ с фрагментом текста, за которым следует короткая гиперссылкаполе с коротким результатом, за которым следует фрагмент текста. Поместите следующий код в модуль:

Sub Select1()
Dim i as long
With ActiveDocument
  For i = .Range.Start to .Range.End
    .Range(i,i).Select
  Next
End With
End Sub

Вставьте точку останова в строку «Следующая».

Затем выполните код один раз с отображаемыми кодами полей и один раз с отображенными результатами полей,Вы должны видеть ход выбора «пауза» либо в начале, либо в конце поля, так как Select продолжает «выбирать» то, что вы на самом деле не видите.

0 голосов
/ 15 октября 2019

Большое спасибо вам обоим за указание на то, что этот подход обречен, но я все еще могу использовать .Start / .End для относительных позиций. В конечном итоге я пытался превратить переданный абзац в HTML с гиперссылками.

Я опубликую то, что сработало, на случай, если кто-то еще его использует.

Function ExtractHyperlinks(rParagraph As Range) As String

    Dim rHyperlink As Range
    Dim wdHyperlink As Hyperlink
    Dim iCaretHold As Integer, iCaretMove As Integer, rCaret As Range
    Dim s As String

    iCaretHold = 1
    iCaretMove = 1
    For Each wdHyperlink In rParagraph.Hyperlinks
        Set rHyperlink = wdHyperlink.Range
        Do
            Set rCaret = ActiveDocument.Range(rParagraph.Characters(iCaretMove).Start, rParagraph.Characters(iCaretMove).End)
            If RangeContains(rHyperlink, rCaret) Then
                s = s & Mid(rParagraph.Text, iCaretHold, iCaretMove - iCaretHold) & "<a href=" & Chr(34) & wdHyperlink.Address & Chr(34) & ">" & IIf(wdHyperlink.TextToDisplay <> "", wdHyperlink.TextToDisplay, wdHyperlink.Address) & "</a>"
                iCaretHold = iCaretMove + Len(wdHyperlink.TextToDisplay)
                iCaretMove = iCaretHold
                Exit Do
            Else
                iCaretMove = iCaretMove + 1
            End If
        Loop Until iCaretMove > Len(rParagraph.Text)
    Next
    If iCaretMove < Len(rParagraph.Text) Then
        s = s & Mid(rParagraph.Text, iCaretMove)
    End If

    ExtractHyperlinks = "<p>" & s & "</p>"

End Function

Function RangeContains(rParent As Range, rChild As Range) As Boolean

    If rChild.Start >= rParent.Start And rChild.End <= rParent.End Then
        RangeContains = True
    Else
        RangeContains = False
    End If

End Function
0 голосов
/ 15 октября 2019

Range.Start возвращает позицию символа от начала документа до начала диапазона;Range.End до конца диапазона.

НО все, что видно в виде символов, не единственные вещи, которые учитываются, и в этом заключается проблема.

Примеры «скрытых» вещей, которые подсчитываются, но не видны:

  • «управляющие символы», связанные с элементами управления содержимым
  • «управляющие символы», связанные с полями (которыетакже означает гиперссылки), который можно увидеть, если результат поля переключается на отображение кода поля с использованием Alt + F9
  • табличных структур (ANSI 07 и ANSI 13)
  • текста со скрытым форматированием шрифта«

По этой причине использование Range.Start и Range.End для получения« реальной »позиции в документе не является ни надежным, ни рекомендуемым. Свойства полезны, например, для установки положения одного диапазона относительно положения другого.

Вы можете получить несколько более точный результат, используя Range.TextRetrievalMode логические свойства IncludeHiddenText и IncludeFieldCodes,Но они не влияют на структурные элементы, связанные с элементами управления содержимым и таблицами.

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