Wordドキュメント上で指定した段落以外の段落を折り畳む

Wordドキュメント上で指定した段落以外の段落を折り畳む

段落を折り畳むことができる

知らなかった。

Wordの標準機能にあった。

百聞は一見に如かず。次をご覧いただきたい。

f:id:akashi_keirin:20200218203812g:plain

「百聞は一見に如かず」と偉そうに言った割にはわかりにくい画像ですまないw

見出しスタイルを当てた段落は、左側に「・」(ポツ)が付く。

んで、このポツにカーソルを近づけると、小さな三角形が表示される。

そいつをクリックしてやると、その見出しに属する本文が折り畳まれたり、展開されたりするのだ。

こいつをVBAで操ってみる。

[Paragraph].CollapsedStateプロパティ

[Paragraph].CollapsedStateというプロパティがある。

こいつがTrueだとその見出しに属する本文が折り畳まれ、Falseだと展開される(表示される)という仕組みらしい。

ちなみに、おなじみコチラの解説によると、

Returns or sets whether the specified paragraph is currently in a collapsed state. Read/write Boolean.

とのこと。

指定した見出しスタイルに指定したキーワードが含まれている段落のみ表示するメソッド

長ったらしくて意味が取りづらくてすまぬ。

たとえば、

f:id:akashi_keirin:20200218203805j:plain

このようなドキュメント(笑)があったとして、たとえば、「【安倍晋三内閣総理大臣】」という見出しの段落だけを表示して、他の見出しの段落本文は折り畳んでしまおう、ということ。要するに、

f:id:akashi_keirin:20200218203807j:plain

こんな状態にしたい、ということ。

リスト1
Public Sub showOnlySpecifiedParagraph(ByVal tgtDocument As Document, _
                                      ByVal styleNameKey As String, _
                             Optional ByVal headerKey As String)
'///指定したスタイル名の見出しの段落のみ表示し、他は折り畳む。'
'///headerKeyを指定すれば、そのキーワードを含む見出しの段落のみを表示。'
'///styleNameKey:表示する段落の見出しスタイルの名前(のキーワード)'
'///headerKey:   表示したい見出しのキーワード。'

  Dim para As Paragraph
  For Each para In tgtDocument.Paragraphs
    With para
      '段落名にstyleNameKeyが含まれていなければContinue'
      If InStr(1, .Style, styleNameKey) = 0 Then GoTo Continue
      'headerKeysが指定されていなければ折り畳む'
      If headerKey = "" Then _
       .CollapsedState = True: GoTo Continue
      '段落のテキストにheaderKeyが含まれていなければ折り畳む'
      If InStr(1, .Range.Text, headerKey) = 0 Then
        .CollapsedState = True
      Else
        .CollapsedState = False
      End If
    End With
Continue:
  Next
End Sub

処理の手順は細かくコメントを入れたので、それを見ればだいたいわかると思う。

For Each ~ Nextで全ての段落を巡回し、

段落のスタイル名にstyleNameKeyで指定したキーワードが含まれていて、なおかつその見出し段落の文字列にheaderKeyで指定したキーワードが含まれていたら、CollapsedStateプロパティをFalseにし(つまり、折り畳まない。)、それ以外のときはTrueにする(つまり、折り畳む。)

というだけのもの。

このメソッドを、先ほどの

f:id:akashi_keirin:20200218203805j:plain

のドキュメント(笑)に対して、次のコードで使ってみる。

スト2
Private Sub test00()
  Call showOnlySpecifiedParagraph(ActiveDocument, _
                                  "見出し 2", _
                                  "安倍晋三")
End Sub

スタイル名に「見出し 2」という文字列を含み、なおかつ見出しに「安倍晋三」という文字列を含む段落の本文だけを残し、他の段落の本文は折り畳む、というマクロ。

コイツを実行すると、

f:id:akashi_keirin:20200218203807j:plain

こうなる。

改良

しかし、上掲のshowOnlySpecifiedParagraphメソッド。困ったことに見出しのキーワードが一つしか指定できない。

つまり、たとえば先のドキュメント(笑)の場合、「議長と銭田掏次郎委員の発言だけを表示させたい」という場合には対応できないのだ。

これはイマイチ。

そこで、先の第3引数headerKeyに複数のキーワードが指定できるように改良する。

リスト3
Public Sub showOnlySpecifiedParagraph( _
             ByVal tgtDocument As Document, _
             ByVal styleNameKey As String, _
    Optional ByRef headerKeys As Variant)    '……(1)'
'///指定したスタイル名の見出しの段落のみ表示し、他は折り畳む。'
'///headerKeysを指定すれば、そのキーワードを含む見出しの段落のみを表示。'
'///styleNameKey:表示する段落の見出しスタイルの名前(のキーワード)'
'///headerKeys:  表示したい見出しのキーワード。配列か値で渡す'

  'headerKeysが省略されていれば、""にする。'
  If IsEmpty(headerKeys) Then headerKeys = ""    '……(2)'
  'headerKeysが配列でなければ、文字列にして要素数1の配列化'
  If Not IsArray(headerKeys) Then    '……(3)'
    headerKeys = Array(CStr(headerKeys))
  End If
  Dim para As Paragraph
  For Each para In tgtDocument.Paragraphs
    With para
      '段落名にstyleNameKeyが含まれていなければContinue'
      If InStr(1, .Style, styleNameKey) = 0 Then GoTo Continue
      'headerKeysが指定されていなければ折り畳む'
      If headerKeys(0) = "" Then _
       .CollapsedState = True: GoTo Continue
      '段落のテキストにheaderKeyが含まれていれば折り畳まない'
      If isToCollapse(.Range.Text, headerKeys) Then    '……(4)'
        .CollapsedState = True
      Else
        .CollapsedState = False
      End If
    End With
Continue:
  Next
End Sub

Private Function isToCollapse( _
             ByVal tgtHeaderText As String, _
             ByRef tgtArray As Variant) As Boolean  '……(5)'
  isToCollapse = False
  Dim i As Long
  For i = LBound(tgtArray) To UBound(tgtArray)
    If InStr(1, tgtHeaderText, tgtArray(i)) > 0  Then
      Exit Function
    End If
  Next
  isToCollapse = True
End Function

変更したのは(1)~(5)の5箇所。

まず(1)の

Public Sub showOnlySpecifiedParagraph( _
             ByVal tgtDocument As Document, _
             ByVal styleNameKey As String, _
    Optional ByRef headerKeys As Variant)

で第3引数を変更。

Variantにして、文字列でも配列でも受け取れるようにした。

(2)の

If IsEmpty(headerKeys) Then headerKeys = ""

は引数チェックその1。

第3引数が省略されていたら、headerKeys""にする。

(3)の

If Not IsArray(headerKeys) Then
  headerKeys = Array(CStr(headerKeys))
End If

は引数チェックその2。

配列でなかったら、値を文字列型にキャストしてheaderKeysに格納。

(4)の

If isToCollapse(.Range.Text, headerKeys) Then
  .CollapsedState = True
Else
  .CollapsedState = False
End If

では、折り畳むかどうかの判定にisToCollapseメソッドを用いている。Trueなら、その段落の本文は折り畳むべし、ということだ。

isToCollapseメソッドは、(5)の

rivate Function isToCollapse( _
            ByVal tgtHeaderText As String, _
            ByRef tgtArray As Variant) As Boolean
  isToCollapse = False
  Dim i As Long
  For i = LBound(tgtArray) To UBound(tgtArray)
    If InStr(1, tgtHeaderText, tgtArray(i)) > 0 Then Exit Function
  Next
  isToCollapse = True
End Function

このとおり。

引数tgtArrayの要素のうち、どれか一つでも見出し段落の文字列に含まれていたらFalse(つまり、折り畳まんでいい)を返す。

使ってみる

次のコードで実験。

リスト4
Private Sub test01()
  Dim var As Variant
  var = Array("銭田", "議長")
  Call showOnlySpecifiedParagraph(ActiveDocument, _
                                  "見出し 2", _
                                  var)
End Sub

第3引数に「銭田」、「議長」という二つのキーワードを格納した配列を渡す。

コイツを実行すると、

f:id:akashi_keirin:20200218203857g:plain

こうなる。無事に「銭田掏次郎委員」と「議長」の発言だけを表示させ、「安倍晋三内閣総理大臣」の発言を折り畳むことができた。

おわりに

議事録なんかで、特定の出席者の発言だけを抽出したいときに便利だと思います。