ブログの記述などに使われるMarkdown記法の中で、表の記述は少し面倒です。
そこで、エクセルで表を作成し、その表をMarkdown記法に変換するツールをPythonの勉強を兼ねて作成しました。
エクセルファイルを読み、Markdown記法に変換してテキストファイルを出力します。
Pythonのパッケージとして openpyxl を使う場合と、 pandas を使う場合について紹介します。
目次
◆できること
エクセルの表をMarkdown記法で記述したテキストファイルに出力します。
エクセル⇒ | Markdownテキスト⇒ | ブラウザ表示 |
---|---|---|
![]() |
![]() |
![]() |
◆考え方
エクセルのファイルを変換してcsvを出力します。
この時に、区切り文字を ,
から |
に変換して出力します。
更に、次の考慮をします。
- エクセルの1行目は見出しとする。ただし、処理ではデータとして扱う。
- セル内で改行している場合
<br>
タグに置き換えて対応 - Matkdownに必要な、見出しと内容の区切り(アラインメント行)を追加
◇Markdown記法の表
Markdown記法の表は、カラムの区切りを |
(縦棒)にし、見出しと内容の間に、-
(ハイフン)で区切りの行(アラインメント行)を指定します。
Markdown記法の表のサンプル Head1 | Head2 | Head3 --- | --- | --- Data1 | Data2 | Data3 Data4 | Data5 | Data6
◆処理内容
Pythonにはエクセルを扱うパッケージがいくつか提供されています。
今回は、openpyxlとpandasを使用した場合について説明します。
pandasの方が短いステップ数で実装できますが、パッケージは大きいです。
- エクセルファイルをロードする。
読み取り専用read_only=True
、値として読むdata_only=True
_wb = oxl.load_workbook( filename=input_file, read_only=True, data_only=True)
- 扱うシートを先頭のシートにする。
_sheet = _wb.worksheets[0]
- 扱うシートを先頭のシートにする。
- 改行されているセルの改行文字を
<br>
に置換
シートのセルを内包表記(行、列で)で置換したセルに代える
_rows = [[str(x).replace("\n", "<br>") for x in _rows] for _rows in _sheet.values]
- Markdownの表のアラインメント行データを作成(値を「
---
」として行追加)
列数分のリストを内包表記で作成
kugiri = ["---" for _ in range(_sheet.max_column)]
- 元のリストを1行目とそれ以外に分割して間にアラインメント行データを挿入
dfs = _rows[:1] + [kugiri] +_rows[1:]
- csvファイルに出力 (
Write_csv(output_path, [], dfs)
メソッド)- ファイルを開く
with open(file_name, encoding="utf_8_sig", mode="w", newline="\n") as f:
- 区切り文字「
|
」を指定
_writer = csv.writer(f, delimiter="|")
- すべてのデータを出力
_writer.writerows(rows)
- ファイルを開く
◇pandasの場合
- エクセルファイルをリードする。
ヘッダーなしとするheader=None
dfs = pd.read_excel(input_file, header=None)
※xlsxファイルをpandasで読むにはopenpyxlが必要(importは不要、インストールは必要) - 改行されているセルの改行文字を
<br>
に置換
ヘッダーなしで読むことで1行目のデータも置換対象とする
dfs.replace("\n", "<br>", True, regex=True)
※DataFrameのreplace()メソッドは、各要素を置換する
※replace()メソッドで文字列の一部を置換する場合は、正規表現(regex=True
)で行う - Markdownの表のアラインメント行データを作成(値を「
---
」として行追加)
列数分の辞書を内包表記で作成
kugiri = {col:"---" for col in dfs.columns}
- 元のリストを1行目とそれ以外に分割して間にアラインメント行データを挿入
dfs = dfs.iloc[:1].append( kugiri, ignore_index=True).append( dfs.iloc[1:])
- csvファイルに出力
区切り文字(sep="|"
)、行名なし(index=False
)、見出しなし(header=False
)を指定。
dfs.to_csv(output_path, sep="|", index=False, header=False)
◆全体のソース
処理内容では触れていませんが、エクセルファイルの指定をコマンドライン引数から行うようにしています。
また、出力ファイル名は「月日_時分_秒.txt」です。
import openpyxl as oxl import sys, datetime, csv def Write_csv( file_name:str, headers:list, rows:list): """ CSVファイルの出力 utf_8_sig, crlf Args: str: ファイル名 list: ヘッダ用リスト list: 出力データ用リスト """ try: with open(file_name, encoding="utf_8_sig", mode="w", newline="\n") as f: _writer = csv.writer(f, delimiter="|") for header in headers: _writer.writerow(header) _writer.writerows(rows) except Exception as e: print("CSVエラー", e) # コマンドライン引数からエクセルファイル名を取得 if len(sys.argv) < 2: print("error no input file name") sys.exit(1) input_file = sys.argv[1] print("Convert file:{}".format(input_file)) _wb = oxl.load_workbook(filename=input_file, read_only=True, data_only=True) # エクセルファイルの読み込み _sheet = _wb.worksheets[0] # 先頭のシートの取得 # 各セルの改行文字を置換して戻す _rows = [[str(x).replace("\n", "<br>") for x in _rows] for _rows in _sheet.values] kugiri = ["---" for _ in range(_sheet.max_column)] # markdown表のアラインメント行の作成 dfs = _rows[:1] + [kugiri] +_rows[1:] # アラインメント行の追加 _wb.close() output_path = '{}.txt'.format(datetime.datetime.now().strftime("%m%d_%H%M_%S")) Write_csv(output_path, [], dfs) # csvファイルへ出力 print("Convert end")
◇pandas
import pandas as pd import sys, datetime # コマンドライン引数からエクセルファイル名を取得 if len(sys.argv) < 2: print("error no input file name") sys.exit(1) input_file = sys.argv[1] print("Convert file:{}".format(input_file)) dfs = pd.read_excel(input_file, header=None) # エクセルファイルの読み込み dfs.replace("\n", "<br>", True, regex=True) # 各セルの改行文字を置換 kugiri = {col:"---" for col in dfs.columns} # markdown表のアラインメント行の作成 dfs = dfs.iloc[:1].append(kugiri, ignore_index=True).append(dfs.iloc[1:]) # アラインメント行の追加 output_path = '{}.txt'.format( datetime.datetime.now().strftime( "%m%d_%H%M_%S")) dfs.to_csv(output_path # csvファイルへ出力 , sep="|" # 区切り文字 , index=False # 行名を出力しない , header=False # 見出しを出力しない ) print("Convert end")
◇全体のソースの取得先
全体のソースはこちらからも取得できます。
リンク:GitHub juu7g/Python-excel2MD
◆exeファイル
pyinstaller
で exe
ファイルを作成しました。
pyinstaller -F pyファイル名
簡単なプログラムですが、パッケージの大きさで exe
ファイルのサイズがかなり違います。
ちなみに、 pyinstaller
は最小限のパッケージのみをいれた仮想環境で動かしています。
openpyxl
使用:約8MBpandas
使用:約30MB
◇バイナリ取得先
バイナリも公開します。サイズの小さいopenpyxlパッケージを使用したものです。
こちらから取得してください。ダウンロード
◇バイナリの使い方
使い方: excel2md_oxl.exe input_path 位置引数: input_path 入力ファイル名
ダウンロードしたzipファイルを解凍してできたexeファイルを実行します。
出力ファイル名は「月日_時分_秒.txt」です。
◆さいごに
エクセルの表を読んでMarkdown記法の表データに変換してテキストファイルに出力するPythonプログラムを紹介しました。
短いプログラムなので『考え方』を読んで、実際に作ってみて、うまくいかなかったら『処理内容』を読んでみるという読み方もあるかなと思います。
今回は、先頭のシートしか処理していないので、シートの指定を可能にするなどの拡張をしても良いのかなと思っています。
これで少し量の多い表でもMarkdownの表にするのが楽になると思います。
◇ご注意
本記事は次のバージョンの下で動作した内容を基に記述しています。
- Python 3.8.5
- openpyxl 3.0.5
- pandas 1.2.2
ご利用に際しては、『免責事項』をご確認ください。
お気づきの点がございましたら『お問い合わせ』からお問い合わせください。
追加:2022-08-08
■更新情報
◆参考
- openpyxl解説:openpyxl による Excelファイル操作方法のまとめ | ガンマソフト株式会社
- pandas解説:pandasでExcelファイル(xlsx, xls)の読み込み(read_excel) | note.nkmk.me
- openpyxlマニュアル:openpyxl - A Python library to read/write Excel 2010 xlsx/xlsm files — openpyxl 3.0.6 documentation
- pandasマニュアル:API reference — pandas 1.2.3 documentation