Sublime3でExcel表をMarkdownテーブルに変換するプラグインを作成

# 概要

Markdownでテーブルを書くのは、結構面倒ですよね。
Sublime Text3で、Excel表をmarkdownテーブル変換するプラグインを作ります。

# 環境

- Windows10
- Sublime Text3
- Python3

# 完成形

プラグインが完成すると以下のように、簡単にMarkdownテーブルに変換することができます。

### 操作手順
1. エクセルを範囲指定してコピー
1. Sublime Textに貼り付け
1. Sublime Textに張り付けたテキストを範囲選択
1. 「Ctrl + Shift + P」でコマンドパレットを開く
1. コマンドパレット上で、作成したショートカットを選択し実行

![Animation3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/473097/60a04d10-0adb-f05f-ebd3-5719589015c0.gif)

↓実際変換されたMarkdownテーブルがこれです

**しりとりと助数詞の関係性について**

| ID | 名前 | 助数詞 |
| - | - | - |
| 1 | リンゴ | 個 |
| 2 | ゴリラ | 頭 |
| 3 | ラッパ | 本 |
| 4 | パセリ | 本 |


# プラグインの作成

## 作成ファイル

Windowsの場合は、`%AppData%\Sublime Text 3\Packages`の配下にプラグイン用のファイルを作成する必要があります。


- {プラグイン名}.py
  - プラグインのメイン処理を記載
- {プラグイン名}.sublime-commands
  - コマンドパレットで呼び出すコマンドを定義

今回は、myconvertというプラグイン名で作成するので、下記ファイルを作成していきます。

- myconvert.py
- myconvert.sublime-commands

# 処理部分の作成

まずは、実際に作成したコードです。
後ほど捕捉はしますが、コメントを見ていただくと大体処理の流れがわかるかと思います。

```myconvert.py
import sublime
import sublime_plugin

import re

def checkSel(sel_range):
    """選択範囲の確認
    """
    if sel_range.empty():
        sublime.message_dialog("選択範囲が指定されていません")
        exit()
        
class ExcelTableToMarkdown(sublime_plugin.TextCommand):
    """Excelテーブルをmarkdownテーブルに変換
    """
    def run(self, edit):
        # 選択範囲の取得
        sel_area = self.view.sel()

        # 選択範囲の確認
        checkSel(sel_area[0])

        for i in range(len(sel_area)):

            # 選択範囲を文字列として取得
            sel_string = self.view.substr(sel_area[i])

            # 整形する
            text = re.sub("\"(.*?)\"", lambda m: re.sub('\n','<br>',m.group(1), flags=re.MULTILINE), sel_string, flags=(re.MULTILINE | re.DOTALL))
            text = re.sub("^(.+)","| \\1", text, flags=re.MULTILINE )
            text = re.sub("(.)$","\\1 |", text, flags=re.MULTILINE )
            text = re.sub("\t"," | ", text, flags=re.MULTILINE )

            # 改行区切りでlistに変換
            textList = text.splitlines()

            # 選択範囲に空行が含まれることを考慮して、1行目を断定する
            firstRow = 0
            for j in range(len(textList)):
                if textList[j]:
                    firstRow = j
                    break

                # 空行しかない場合は処理を終了
                if j == len(textList)-1:
                    exit()

            firstLine = textList[firstRow] # 1行目を取得する
            columNum = firstLine.count('|')-1 # columnの数を計算する

            # 2行目を組み立てる
            secondLine = "|"
            for j in range(columNum):
                secondLine = secondLine + " - |"

            textList.insert(firstRow+1,secondLine) # 2行目を挿入する
            text = '\n'.join(textList) # listをテキストに戻す

            # 選択範囲と入替え
            self.view.replace(edit, sel_area[i], text)

```

### 補足説明　import

```python
import sublime
import sublime_plugin
```

import部分ですが、sublimeのプラグイン専用の**sublime**と**sublime_plugin**読み込んでいます。これにより、選択範囲の情報取得や操作ができるようになります。

### 補足説明　関数

```python
def checkSel(sel_range):
    """選択範囲の確認
    """
    if sel_range.empty():
        sublime.message_dialog("選択範囲が指定されていません")
        exit()
```

checkSel()は、選択範囲が空かどうかを判定する関数です。
1度しか呼び出されていませんが、今後別の変換処理を作るときに便利なので、関数に切り出しています。

### 補足説明　メイン処理のクラス名

```python
class ExcelTableToMarkdown(sublime_plugin.TextCommand):
```


ショートカットを登録する際に、定義したクラスの名称で呼び出すことになります。
また、クラス名はパスカルケース（要素語の最初を大文字）で書く必要があります。


### 補足説明　選択範囲を配列化

```python
    # 選択範囲の取得
    sel_area = self.view.sel()

    # 選択範囲の確認
    checkSel(sel_area[0])

    for i in range(len(sel_area)):

        # 1行単位の処理は省略...
```

選択範囲を取得し１行ずつ処理しています。
この処理部分は、ほかのSublimeプラグイン開発でも応用できるかと思います。



# ショートカットの作成

実際に作成した定義ファイルです。

```json:myconvert.sublime-commands
[
    {"caption":"myconvert table excel >> markdown","command":"excel_table_to_markdown"}
]
```

### 項目説明
- caption: コマンドパレッドで表示される文字。すべて打ち込む必要がないので、分かりやすいキーワードが入っていると良いと思います。
- command: メイン処理のクラス名を記載します。だたし、パスカルケースではなくスネークケース(要素語をアンダースコアで連結)で書く必要があります。


# 最後に

今回は、Markdownテーブルの変換するプラグインを作成しましたが、
それ以外にも「URLのGETパラメータで改行」や「SQLを整形」などもGitHubに公開しています。
興味がある方は、コードを見てみてください。

https://github.com/ishi720/sublime3_query_ope_tool

ここまで読んで頂きありがとうございました。