WordでMarkdownっぽいことをするマクロ(Word)

WordでMarkdownっぽいことをするマクロ(Word)

やりたいこと

  • 先頭に# を付けた段落には、「#」の数に応じた階層の「見出し」スタイルを当てる。
  • その他の「標準」スタイルの段落には、「本文」のスタイルを当てる。

こういうことがしたい。

仕事柄、文章の資料を作成することが多い。下書き段階ではテキストエディタでぐりぐり書いていきたいのだが、見出しとかの表現がmachine-readableでなくていまいちだった。

「だったら、Markdown的に書けるようにしたらいいんじゃね?」と思って、冗談半分で作り始めたのがきっかけ。

今ではいろんな表現に対応した立派な〝インチキMarkdownマクロ〟になり、非常に重宝しているのだが、今回は「見出し」だけに対応した簡易ヴァージョンをご紹介、というわけ。

こんなコード

Documentオブジェクトを渡したら、その配下のParagraphsコレクションの要素であるParagraphオブジェクトを一つづつ調べ、先頭に「# 」があったら「#」の数に応じた「見出し」スタイルを、先頭に「# 」がなくて、なおかつ「標準」スタイルの段落なら、「本文」用のスタイルを当てる、というもの。

さっそくコードをお示ししよう。

リスト1
Public Sub SetHeaderStyle(ByVal a_Document As Document)
  Dim tgtDoc As Document
  Set tgtDoc = a_Document
  Dim tgtPara As Paragraph
  Dim tmpLen As Long
  Dim tmpStr As String
  Dim i As Long
  Dim j As Long
  For Each tgtPara In tgtDoc.Paragraphs
    With tgtPara
      With .Range
        '「#」で始まらない段落は飛ばす。'
        If .Characters.Item(1).Text <> "#" Then GoTo Continue
        tmpLen = Len(.Text) - 1 '改段落文字分を引く。'
        '2文字未満なら見出しのわけがないので飛ばす'
        If tmpLen < 2 Then GoTo Continue
        '見出しレベル9でも10字にしかならないので最大10字で切る。'
        If tmpLen > 10 Then tmpLen = 10
        tmpStr = Left(.Text, tmpLen)
        '「# 」が含まれていなかったら飛ばす。'
        If InStr(1, tmpStr, "# ") < 1 Then GoTo Continue
        '先頭が〈「#」の連続+半角スペース〉になっていたら見出し。'
        For i = tmpLen To 2 Step -1    '……(*)'
          If Left(tmpStr, i) = String(i - 1, "#") & " " Then
            tgtPara.Style = "見出し " & CStr(i - 1)
            For j = i To 1 Step -1
              Call .Characters.Item(j).Delete
            Next
          End If
        Next
      End With
    End With
Continue:
    '見出しでない標準スタイルの段落には本文字下げスタイル。'
    If tgtPara.Style = "標準" Then
      tgtPara.Style = "My本文字下げ1"    '……(**)'
    End If
  Next
End Sub

だいたい見ての通りなので、説明は省略。

ただし、「(*)」のところだけ簡単に説明しておく。

For i = tmpLen To 2 Step -1    '……(1)'
  If Left(tmpStr, i) = String(i - 1, "#") & " " Then  '……(2)'
    tgtPara.Style = "見出し " & CStr(i - 1)    '……(3)'
    For j = i To 1 Step -1    '……(4)'
      Call .Characters.Item(j).Delete
    Next
  End If
Next

まず、(1)の

For i = tmpLen To 2 Step -1

では、段落先頭から最大10まで(段落の文字数が、改段落マークを除いて10字未満なら、10よりも小さな数になる。)の数値を表す変数tmpLen1づつ減じながらループする。

(2)の

If Left(tmpStr, i) = String(i - 1, "#") & " " Then

で、tmpStrに入っている文字列(段落先頭からtmpLen字分切り取った文字列。)を先頭からi字分切り取った文字列を調べる。

たとえば、i4のときに、tmpStrの先頭i文字、つまり先頭4字が「### 」(#3個と半角スペース)だったら、見出しレベル3を適用すれば良いことになる。

(2)の条件式がTrueになると、(3)の

tgtPara.Style = "見出し " & CStr(i - 1)

で、当該の段落に「見出し」スタイルを適用する。

先の例でいうと、i4のときには、見出しレベル「3」を適用するのだから、"見出し " & CStr(i - 1)とすれば、めでたく「見出し 3」という文字列を組み立てることができる。

あとは、(4)からの3行、

For j = i To 1 Step -1    '……(4)'
  Call .Characters.Item(j).Delete
Next

で、見出しであることを表す「# 」を削除する。

コレクションの要素を削除すると、自動でインデックスが繰り上がる仕様なので、こうしないとおかしなことになる。

「削除はケツから!」は常識中の常識である!

ちなみに、(**)

If tgtPara.Style = "標準" Then
  tgtPara.Style = "My本文字下げ1"
End If

のところに出てくる「My本文字下げ1」というのは、私が勝手に作ったスタイルの名前。めちゃくちゃダサい名前にしてしまって、激しく後悔している。

使ってみる

原稿をテキストエディタで作って、Wordに貼り付ける。

f:id:akashi_keirin:20220314075418p:plain

次のリスト2を実行する。

スト2
Private Sub test01()
  Dim tgtDoc As Document
  Set tgtDoc = ActiveDocument
  Call SetHeaderStyle(tgtDoc)
End Sub

すると、一瞬で

f:id:akashi_keirin:20220314075421p:plain

こうなる。

ナビゲーション ウインドウも

f:id:akashi_keirin:20220314075425p:plain

この通り!

バッチリである!

おわりに

このほか、アンダーライン、太字強調、傍点、ルビ、引用、箇条書きに対応済み(ただし、箇条書きは1階層にしか対応していません。)なのですが、めちゃくちゃ便利です。

今回ご紹介した「見出し」対応だけでも十分便利だと思います。