【问题标题】:What does a hyperlink range.start and range.end refer to?超链接 range.start 和 range.end 指的是什么?
【发布时间】:2020-02-11 21:19:59
【问题描述】:

我正在尝试处理包含超链接的 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

但是,#s 之间的输出与超链接不完全匹配,并且超出了一个或两个字符。那么如果 .Start 和 .End 不返回 char 位置,它们返回什么?

【问题讨论】:

    标签: vba hyperlink ms-word range


    【解决方案1】:

    这有点简化,但这是因为 rEverything 计算超链接之前的所有内容,然后是超链接字段代码中的所有字符(包括每个字符 1 个字符)开始和结束字段代码大括号),然后是超链接字段中的所有字符结果,然后是字段之后的所有字符。

    但是,如果 TextRetrievalMode.IncludeFieldCodes 设置为False 并且仅在 TextRetrievalMode.IncludeFieldCodes 设置为 True 时包含字段 code

    所以字符数总是小于 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 会一直“选择”您实际上看不到的内容。

    【讨论】:

      【解决方案2】:

      Range.Start 返回从文档开头到范围开头的字符位置; Range.End 到范围的末尾。

      但是所有作为字符可见的东西并不是唯一被计算在内的东西,这就是问题所在。

      被计数但不可见的“隐藏”事物示例:

      • 与内容控件关联的“控制字符”
      • 与字段关联的“控制字符”(也表示超链接),如果使用 Alt+F9 将字段结果切换到字段代码显示,则可以看到该字符
      • 表结构(ANSI 07 和 ANSI 13)
      • 字体格式为“隐藏”的文本

      因此,使用Range.StartRange.End 在文档中获得“真实”位置既不可靠也不推荐。这些属性很有用,例如,设置一个范围相对于另一个范围的位置。

      您可以使用Range.TextRetrievalMode 布尔属性IncludeHiddenTextIncludeFieldCodes 获得更准确的结果。但这些不会影响与内容控件和表格相关的结构元素。

      【讨论】:

      • 感谢您的回复。它是简短的、简单的文本。几句随意的词。没有桌子,没有隐藏的东西。我专门打开了计数域代码,并通过将rEverything.TextRetrievalMode.IncludeFieldCodes 设置为TruerEverything.Text 中的ASCII 值进行了迭代。我正在努力理解那里可能还有哪些其他角色。我不会看到他们都这样做吗?
      【解决方案3】:

      非常感谢你们指出这种方法注定要失败,但我仍然可以使用 .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
      

      【讨论】:

        猜你喜欢
        • 2016-05-20
        • 2011-02-20
        • 1970-01-01
        • 1970-01-01
        • 2020-08-22
        • 1970-01-01
        • 1970-01-01
        • 2019-08-02
        • 2017-05-30
        相关资源
        最近更新 更多