以前,『Excel ワークシートの一括 CSV 変換』記事で,Spreadsheet::
しかしその後,このプログラムだと,JISX 0213 の文字のうち Unicode コードポイント U+20000 以上の拡張領域にある漢字がすべて x'EFBFBD' に文字化けしてしまうことがわかった。Spreadsheet::
入力の Excel ファイル (jisx0213-extarea-tbl.

図 1. 入力 Excel: jisx0213-extarea-tbl.xls

図 2. 出力 CSV (漢字が文字化け)
そこで,文字化け対策として,今回は Python3 言語を用いて,Excel - CSV 変換プログラムを書いた。果たして,U+20000 以上の拡張領域の文字もきちんと抽出できた。
以下,Excel から CSV を抽出するプログラム,CSV から Excel 2007 ブックを生成するプログラム,及び Excel ブックの属性変更を行うプログラムの例について示す。Excel データを読み書きする openpyxl 及び,データサイエンスライブラリ Pandas のモジュールが必要なので,あらかじめ “pip install pandas openpyxl” にて組み込んでおく。
なお,本稿で作成するプログラムの前提として,CSV のセパレータは “|”(vertical line, x'7c') としている。また,データ中にセパレータ文字を使う場合のエスケープ文字は,“\”(backslash, x'5c') としている。
xlsxtocsv.py: Excel から CSV を抽出する
Excel ブックに含まれるすべてのシートについて,データを CSV 形式で出力する手順は概ね次のとおりである。
- pandas の ExcelFile("Excel ファイル名") 関数により,Excel ブックオブジェクト (ここでは xls_book とする) を読み込む。
- xls_book.
sheet_names で参照できる Excel シート名毎に以下処理を行う。 - xls_book.
parse 関数により,シートのデータを読み込んで,pandas DataFrame オブジェクト (ここでは df) に格納する。(sheet_name=シート名, opts) - DataFrame オブジェクト df の to_csv
(CSV ファイル名, opts) メソッドにより,指定したファイルに CSV データを書き出す。
実装 xlsxtocsv.py のコードを以下に示す。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | #!/usr/bin/env python3 # -*- coding: utf-8 -*- # # xlsxtocsv.py: Excel to CSV # # 2020(c) isao yasuda, All Rights Reserved. # $Id: xlsxtocsv.py 488 2020-04-11 16:02:10Z isao $ # # DESCRIPTION # ----------- # - usage: xlsxtocsv.py xlsx-file # - Excel Book を読んで,Sheet名.csv を書き出す # - セパレータは '|' # - " クォートしないようにする。(panda.DataFrame.to_csv quotechar='\\' 指定) import os import sys import pandas as pd # プログラム名 pn = os.path.basename(sys.argv[ 0 ]) # 引数チェック if len (sys.argv) ! = 2 : print ( "usage:" , pn, "excel-file" ) exit( 1 ) print ( "*" , pn + ":" , "Excel file:" , sys.argv[ 1 ]) # Excel Book 読み込み xls_book = pd.ExcelFile(sys.argv[ 1 ]) # シートごとに内容を"シート名.csv"ファイルに書き出す # - シートが存在するだけループ for sht_name in xls_book.sheet_names: # シートオブジェクトを DataFrame にセット df = xls_book.parse(sheet_name = sht_name, header = None ) csv_fname = sht_name + '.csv' print ( "*" , pn + ": Sheet:" , sht_name, "output to" , csv_fname) # DataFrame を「シート名.csv」で CSV 出力 df.to_csv(csv_fname, index = False , header = False , sep = '|' , quotechar = '\\' ) |
本プログラムの実行の様子を以下に示す。CSV 出力結果は図 3 のとおりである。文字化けせず正しく出力されている。
1 2 3 4 | $ /xlsxtocsv .py jisx0213-extarea-tbl.xls * xlsxtocsv.py: Excel file : jisx0213-extarea-tbl.xls * xlsxtocsv.py: Sheet: jis0213-win output to jis0213-win.csv $ |

図 3. CSV 出力結果
csvtoxlsx.py: 複数の CSV ファイルから Excel ブックを生成する
複数の CSV ファイルを Excel シートとして格納し,Excel ブックを生成するプログラムを書く。その主な手順は以下のとおりである。
- 指定した CSV ファイル毎に以下を行う。
- csv モジュールの reader 関数で CSV データをオブジェクト (ここでは reader) に読み込む。
- reader オブジェクトから行のリストを組み立て,このリストから pandas DataFrame (ここでは sdf) を生成する。
- pandas の ExcelWriter
(Excel ファイル名, engine="openpyxl"[, opt]) 関数によりライタ (ここでは writer) を定義する。このとき,最初のシートの場合,opt に何も指定せず,2 シート目以降の場合,opt に mode="a" (追加モード) を指定する。 - DataFrame オブジェクト sdf の to_excel
(writer, sheet_ メソッドにより,writer 指定で CSV ファイルに対応した Excel シートを生成する。name=シート名, opts)
実装 csvtoxlsx.py のコードを以下に示す。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 | #!/usr/bin/env python3 # -*- coding: utf-8 -*- # # csvtoxlsx.py: CSV files to Excel Book # # 2020(c) isao yasuda, All Rights Reserved. # $Id: csvtoxlsx.py 488 2020-04-11 16:02:10Z isao $ # # DESCRIPTION # ----------- # - usage: csvtoxlsx.py xlsx-file 0 1 2.. # - 0.csv, 1.csv,.. を読んで 0, 1,.. シート名からなる xlsx-file を生成する。 # - CSV のセパレータ '|'; 引用文字 \; エスケープ文字 \\; import os import sys import csv import pandas as pd # CSV ファイルを読んで DataFrame を生成する関数 def genCSVDataFrame(csv_fname): with open (csv_fname, newline = '') as csvf: reader = csv.reader(csvf, delimiter = '|' , quotechar = '\'' , escapechar = '\\' ) csvlist = [row for row in reader] return pd.DataFrame(csvlist) # 主処理 # プログラム名 pn = os.path.basename(sys.argv[ 0 ]) # 引数チェック argc = len (sys.argv) if argc < 3 : print ( "usage:" , pn, "xlsx-file 0 1 2 .." ) print ( " 0, 1,..4: basename of 0.csv, 1.csv,.. 4.csv" ) exit( 1 ) # Excel ファイルがすでに存在していたら削除 xlsx_fname = sys.argv[ 1 ] if os.path.exists(xlsx_fname): os.remove(xlsx_fname) print ( "*" , pn + ": old Excel Book:" , xlsx_fname, "removed." ) # 引数の CSV ファイルごとに Excel シートを追加 # - 指定 CSV ファイル (sys.argv[2] 〜 (argc - 1)) 毎にループ # - openpyxl エンジンで Excel シートとして出力 for i in range ( 2 , argc): sht_name = sys.argv[i] csvfile = sht_name + '.csv' print ( "*" , pn + ": CSV file:" , csvfile) # CSV DataFrame を Excel に出力 sdf = genCSVDataFrame(csvfile) if os.path.exists(xlsx_fname): # すでに xlsx ファイルがあれば,当該シートを追加(二つ目以降の CSV ファイル) with pd.ExcelWriter(xlsx_fname, engine = "openpyxl" , mode = "a" ) as writer: sdf.to_excel(writer, sheet_name = sht_name, index = False , header = False ) print ( "*" , pn + ": added Sheet:" , sht_name, "to" , xlsx_fname) else : # 存在しなければ,当該シートで xlsx ファイルを作成(最初の CSV ファイル) with pd.ExcelWriter(xlsx_fname, engine = "openpyxl" ) as writer: sdf.to_excel(writer, sheet_name = sht_name, index = False , header = False ) print ( "*" , pn + ": added Sheet:" , sht_name, "to new" , xlsx_fname) |
1 2 3 4 5 | $ . /csvtoxlsx .py jisx0213-extarea-tbl.xlsx jis0213-win * csvtoxlsx.py: old Excel Book: jisx0213-extarea-tbl.xlsx removed. * csvtoxlsx.py: CSV file : jis0213-win.csv * csvtoxlsx.py: added Sheet: jis0213-win to new jisx0213-extarea-tbl.xlsx $ |

図 4. 出力 Excel ブック: jisx0213-extarea-tbl.xlsx
adjustxlsx.py: Excel ブックの属性を変更する
上記 csvtoxlsx.py で生成した Excel ブックのセル属性は,必ずしも利用者の意図に沿ったものとは限らず,フォントや,セルの格納文字列の長さに応じた幅・折り返し,左寄せ等の配置,といった属性を指定したい場合がある。
Excel ブックを読み,セル属性を設定変更して,当該ブックを上書きするプログラムを書く。その主な手順は以下のとおりである。
- openpyxl モジュールの load_
workbook 関数を用いて,Excel ブックオブジェクト (ここでは wb) を取得する。(Excel ファイル名) - wb.sheetnames で得られるシート名リストの各シート名毎に以下を行う。
- 当該シート名をアクティブに設定する。ここではアクティブシートオブジェクトを ws とする。
- 設定したい属性に応じて,ws の行・列・セル単位で Font や Alignment によって属性をセットしていく。フォント属性や列幅は列単位で,行の高さは行単位でセットできる。水平・垂直の寄せ,折り返し表示等の配置属性については,セル単位に設定する必要があるようである。
- 属性設定を完了したら,ws.save(Excel ファイル名) でファイルをセーブし,ws.close() でクローズ処理を行う。
実装 adjustxlsx.py のコードを以下に示す。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | #!/usr/bin/env python3 # -*- coding: utf-8 -*- # adjustxlsx.py - Excel 行・列幅,セル属性の調整 # 2020(c) isao yasuda, All Rights Reserved. # $Id: adjustxlsx.py 488 2020-04-11 16:02:10Z isao $ # DESCRIPTION # ----------- # - usage: adjustxlsx.py xlsx-file # - Excel Book を読んで,シートごとに以下を行う # (1)列幅を設定する。 # (2)行高を設定する。 # (3)フォント,テキスト配置のセル属性を設定する。 # - 同一ファイルに格納する。 import openpyxl as px from openpyxl import Workbook from openpyxl.styles import Alignment, Font import os import sys # プログラム名 pn = os.path.basename(sys.argv[ 0 ]) # 引数チェック if len (sys.argv) ! = 2 : print ( "usage:" , pn, "xlsx-file" ) exit( 1 ) # Excel Book オブジェクト wb = px.load_workbook(sys.argv[ 1 ]) # シート名のリストを取得 sht_nm = wb.sheetnames # セル属性 # - フォント: メイリオ, 11pt, ボールド無, 立体, アンダーライン無 font1 = Font(name = 'メイリオ' , size = 11 , bold = False , italic = False , vertAlign = None , underline = 'none' , strike = False ) # - 配置: 左寄せ, 上寄せ, 折り返し表示, インデント無 aligment1 = Alignment(horizontal = 'center' , vertical = 'center' , wrapText = True , indent = 0 ) # シート毎の設定 # - シートの数だけループし,セル属性を設定 # - インデックス i = 0: 文字; 1: コードポイント sht_len = len (sht_nm) for i in range ( 0 , sht_len): # アクティブシートの選択 ws = wb[sht_nm[i]] print ( "*" , pn + ": sheet:" , sht_nm[i], "attribute setting" ) # 列毎にフォント属性を設定 for coln in [ "A" , "B" ]: ws.column_dimensions[coln].font = font1 # 列毎に列幅を設定 # A列 B列 # 漢字|コードポイント # 6 12 ws.column_dimensions[ "A" ].width = 6 ws.column_dimensions[ "B" ].width = 12 # 行毎に行高を設定 # - 18pt # 当該行の列毎に配置属性を設定 # - 定義した alignment1 属性 # ws.max_row: シートの有効行数 print ( "*" , pn + ":" , sht_nm[i], "items:" , ws.max_row) # 行数 rowmax = ws.max_row + 1 # ループの range 境界値 for row in range ( 1 , rowmax): # 先頭行から最終行まで ws.row_dimensions[row].height = 18 for col in range ( 1 , 3 ): # 行・列 (セル) 毎に配置属性を設定 ws.cell(row = row, column = col).alignment = aligment1 # Excel Book の保存・クローズ wb.save(sys.argv[ 1 ]) wb.close() |
本プログラムの実行の様子を以下に示す。生成された Excel ブックは図 5 のとおりである。フォント (メイリオ),漢字及びそれに対する Unicode コードポイントの列幅 (それぞれ 6,12),行高 (18),配置 (中央揃え) が,それぞれ ( ) 内の属性に変更されている。
1 2 3 4 | $ . /adjustxlsx .py jisx0213-extarea-tbl.xlsx * adjustxlsx.py: sheet: jis0213-win attribute setting * adjustxlsx.py: jis0213-win items: 303 $ |

図 5. 属性変更後 Excel ブック: jisx0213-extarea-tbl.xlsx
参考資料
pandas,openpyxl の API の詳細は以下のドキュメントを参考にしていただきたい。
- pandas: pandas documentation
- openpyxl: openpyxl - A Python library to read/write Excel 2010 xlsx/xlsm files
筆者が学んだ Python3 の参考書をあげておく。