Excel表をMarkdownへ変換

Markdownを知ってから、使いやすさからMarkdownでものを書くことが多くなり、勉強やアイディアのメモ、議事録などで使っていますが、表だけは書きづらく感じています。

そこで、Excelで表を作ってからMarkdownへ変換するプログラムが無いかと思って調べてみると、Javaなどの言語で書かれた変換のプログラムやWeb上で変換するサービスが見つかりましたが、自分の思うものが見つからなかったので、Excel VBAで自作することにしました。
作るにあたり下記の点に気をつけました。

  • 簡単に使える
    Excelで作成したあと、少ない手順で実行・変換できて、使いたい場所へのコピーが容易であるということです。

  • ネットワークを必要としない
    ノートパソコンを外で使っているとネットワークが無い環境が意外と多くあります。 Free Wi-Fiはセキュリティ面が心配です。 Excel VBAであれば基本的に問題ありません。

  • 簡単に移植できる
    プログラムのコードをコピー&ペーストするだけで使えるようになるのが理想です。 UserFormは使わないようにします。

変換結果をクリップボードに保存するということを考えたのですが、その部分が一番大変でした。

検索するとDataobjectを使う方法が多く出てきますが、環境によりうまく動かないことがあるようです。
また、Microsoft Forms 2.0 Object Libraryを参照設定する必要がありますが、参照リストに通常では表示されず、パスでDLLを指定しなくてはならないということで、移植性が悪いと感じました。

そこで、msdnのページを参考に、Windows APIを使うことにしました。
Send Information to the Clipboard

下記コードをモジュールに貼り付けExportMarkdownを実行すると、アクティブシートにある表がMarkdownに変換されてクリップボードに保存されます。
使用の流れとしては下記3手順で変換することができます。
(プログラムが標準Moduleに書かれているExcelを使用している前提です)

  1. Excelで表を作る
  2. ExportMarkdownを実行する
  3. マークダウンを使いたい場所に貼り付けする

使用する際にいくつか条件があります。

  • alignは一番上の行で決まる(標準の場合は中央揃え)
  • 表は罫線が無くても使用できる
  • 表の位置はどこにあっても認識する。
  • シート内に存在する表は一つまで
  • 余分な文字や罫線があると誤認識する
  • 結合されたセルには非対応

usedRangeでうまく範囲が取得できる表であれば問題ありません。
Worksheet.UsedRange プロパティ (Excel)

細かい説明は省略しますが、大まかには下記4つを行っています。

  • usedRangeを使って表の位置を取得
  • 左上から順番にセルの値を確認しながらMarkdownに変換した文字列を変数に代入
  • 2行目ではalignを設定
  • 変数の値をクリップボードにセット

また、クリップボードにセットする部分は参考ページのプログラムをそのまま使っています。

Option Explicit

'information-to-the-clipboard
Private Declare Function OpenClipboard Lib "user32.dll" (ByVal hWnd As Long) As Long
Private Declare Function EmptyClipboard Lib "user32.dll" () As Long
Private Declare Function CloseClipboard Lib "user32.dll" () As Long
Private Declare Function SetClipboardData Lib "user32.dll" (ByVal wFormat As Long, ByVal hMem As Long) As Long
Private Declare Function GlobalAlloc Lib "kernel32.dll" (ByVal wFlags As Long, ByVal dwBytes As Long) As Long
Private Declare Function GlobalLock Lib "kernel32.dll" (ByVal hMem As Long) As Long
Private Declare Function GlobalUnlock Lib "kernel32.dll" (ByVal hMem As Long) As Long
Private Declare Function lstrcpy Lib "kernel32.dll" Alias "lstrcpyW" (ByVal lpString1 As Long, ByVal lpString2 As Long) As Long

Sub ExportMarkdown()

    Dim usedRange As Range
    Set usedRange = ActiveSheet.usedRange
    
    Dim columnMin As Long
    Dim columnMax As Long
    columnMin = usedRange.Column
    columnMax = columnMin + usedRange.Columns.Count - 1
    
    Dim rowMin As Long
    Dim rowMax As Long
    rowMin = usedRange.Row
    rowMax = rowMin + usedRange.Rows.Count - 1
    
    Dim i As Long, j As Long
    Dim exportStr As String
    'Check header alignment
    For i = rowMin To rowMax
        If i = rowMin + 1 Then
            For j = columnMin To columnMax
                Select Case Cells(i, j).HorizontalAlignment
                    Case xlRight
                        exportStr = exportStr & "|---:"
                    Case xlLeft
                        exportStr = exportStr & "|:---"
                    Case xlCenter
                        exportStr = exportStr & "|:---:"
                    Case Else
                        exportStr = exportStr & "|:---:"
                End Select
            Next
            exportStr = exportStr & "|" & vbCrLf
        End If
        exportStr = exportStr & "|"
        For j = columnMin To columnMax
            exportStr = exportStr & Cells(i, j).Value & "|"
        Next
        exportStr = exportStr & vbCrLf
    Next
    
    Call SetClipboard(exportStr)

End Sub

Public Sub SetClipboard(sUniText As String)
    Dim iStrPtr As Long
    Dim iLen As Long
    Dim iLock As Long
    Const GMEM_MOVEABLE As Long = &H2
    Const GMEM_ZEROINIT As Long = &H40
    Const CF_UNICODETEXT As Long = &HD
    OpenClipboard 0&
    EmptyClipboard
    iLen = LenB(sUniText) + 2&
    iStrPtr = GlobalAlloc(GMEM_MOVEABLE Or GMEM_ZEROINIT, iLen)
    iLock = GlobalLock(iStrPtr)
    lstrcpy iLock, StrPtr(sUniText)
    GlobalUnlock iStrPtr
    SetClipboardData CF_UNICODETEXT, iStrPtr
    CloseClipboard
End Sub

f:id:ArtificialArts:20180207082110j:plain f:id:ArtificialArts:20180207081911p:plain

名前 直径 (km) 表面重力(m/s2) 公転周期(年) 自転周期(日)
太陽 1392038 274 - 27.275
水星 4879.4 3.7 0.241 58.65
金星 12103.6 8.87 0.615 243.0187
地球 12756.3 9.78 1 0.997271
火星 6794.4 3.71 1.881 1.02595
木星 142984 24.79 11.86 0.4135
土星 120536 8.96 29.46 0.4264
天王星 51118 7.77 84.01 0.7181
海王星 49572 11 164.79 0.6712

これでMarkdownで表を書くのが少し楽になりそうです。
使っていく上で使いにくい部分があれば、改善していこうと思います。