【问题标题】:Find nearest Heading above the MS Word table在 MS Word 表格上方查找最近的标题
【发布时间】:2021-02-02 14:02:08
【问题描述】:

我在 Microsoft Word 中以下列方式枚举表格:

Dim doc As Document, t As Table
Set doc = ActiveDocument
For Each t In doc.Tables
Next t

现在我想在表格上方找到最近的具有“标题 2”样式的段落,并将其文本放入变量中。如果可以在不更改文档中的选择焦点的情况下完成它,那就太好了。

我可以枚举文档中的段落,但是如何确定某个段落在某个表格之上?

【问题讨论】:

标签: vba ms-word


【解决方案1】:

我通过建立段落起始位置列表解决了这个问题:

Private Type CaptionRec
  Text As String
  EndPos As Long
End Type

Dim caps() As CaptionRec
Dim i As Long
Dim p As Paragraph
ReDim caps(0)
i = 0
For Each p In doc.Paragraphs
  If p.Style = "Überschrift 2" Then
    i = i + 1
    ReDim Preserve caps(i)
    caps(i).Text = TrimGarbageAtEnd(p.Range.Text)
    caps(i).EndPos = p.Range.Start 'Ok, this should be the end, not the start
  End If
Next p

... 并从数组中找到表格开始和“标题 2”段落之间的最小距离:

Public Function GetClosestCaption(tableStart As Long, ByRef caps() As CaptionRec) As String
  Dim cap As CaptionRec, distance As Long, minDistance As Long, res As String, i As Long
  minDistance = 2147483647 'Max long
  res = ""
  For i = LBound(caps) To UBound(caps)
    cap = caps(i)
    distance = tableStart - cap.EndPos
    If distance >= 0 Then
      If distance < minDistance Then
        minDistance = distance
        res = cap.Text
      End If
    End If
  Next i
  GetClosestCaption = res
End Function

例程在以下循环中被调用:

Public Sub MainRoutine()
  For Each t In doc.Tables
    If table_validity_criteria_go_here Then
      caption = GetClosestCaption(t.Range.Start, caps)
      For Each r In t.Rows
        'Enumerate rows
      Next r
    End If
  Next t
End Sub

【讨论】:

  • 您将通过使用Find 获取标题而不是循环遍历段落来提高代码获取标题的效率。
【解决方案2】:

另一种方法是颠倒逻辑。不是先处理表格再查找关联的标题,而是先找到标题再处理标题级别范围内的表格,例如:

Sub FindHeading2Ranges()
   Dim findRange As Range
   Dim headingRange As Range
   Set findRange = ActiveDocument.Content
   With findRange.Find
      .ClearFormatting
      .Forward = True
      .Wrap = wdFindStop
      .Format = True
      .Style = ActiveDocument.Styles(wdStyleHeading2)
      Do While .Execute
         Set headingRange = findRange.GoTo(What:=wdGoToBookmark, Name:="\HeadingLevel")
         If headingRange.Tables.Count > 0 Then
            ProcessTables headingRange, TrimGarbageAtEnd(findRange.text)
         End If
         findRange.Collapse wdCollapseEnd
      Loop
   End With
End Sub

Sub ProcessTables(headingRange As Range, caption As String)
   Dim t As Table
   For Each t In headingRange.Tables
      If table_validity_criteria_go_here Then
         For Each r In t.Rows
            'Enumerate rows
         Next r
      End If
   Next t
End Sub

【讨论】:

  • 感谢您的努力。表格是主要的,标题 - 次要的。并非每个匹配表都有上面的标题。我测试了你的脚本。它在 headingRange.Text 中包含标题文本以及其后段落的文本,尽管该段落有另一个样式名称。我的变体运行缓慢,尤其是当从 Delphi 应用程序调用 Word 时,但完全符合我的需要。
  • @Paul - 我在发布之前彻底测试了我的代码,并且可以保证 findRange.text 只包含找到的标题 2 样式的文本,但是我不知道你的 TrimGarbageAtEnd 函数做了什么。您正在测试的文档也可能存在问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-12-29
  • 2017-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-06
  • 1970-01-01
相关资源
最近更新 更多