経緯
最近参画していた案件でタイトル通りの機能が必要であったため。
作成した内容を抜粋。
Github
機能
- エンコード、改行コードを指定できる。
- スキップする行を指定できる。
- 文字列か数値か判断して、出力形式を分ける。
- 小数(パーセント)は桁数指定
- 結合セルもよしなに処理。
ライブラリについて
当初は、エクセル上00.0%書式のところ、ロジック上で書式を読み取り判断する仕様だった為、
書式データも読み取り可能なpandas、openpyxlを検討した。
採用
- 速かったから。2000行で4秒程度。20000行で40秒ぐらい
- 結合セルも補間して処理してくれるから。
- 書式読み取り不要になった為。
不採用
- エクセル良い取って、csv出力するだけにしたら、dataflameは機能過多で複雑に感じたから。
- 重たかったから。2000行で15秒。xlrdの約三倍。
書式データを保持しているからか、初期読み込みに時間がかかる模様。 - 結合セルをよしなに処理してくれなかったから。
ロジック詳細
import
import xlrd
エクセル読み取り
xls = xlrd.open_workbook(INPUT_XLSX)
sheet = xls.sheet_by_index(0)
rows = sheet.nrows # 行数
cols = sheet.ncols # 列数
for r in range(0, rows):
for c in range(0, cols):
cell = sheet.cell(r,c)
cell.value # 値を取得
cell.ctype # 値のタイプを取得
CSV出力
エンコード、改行コード
file = open(OUTPUT_CSV, 'w', encoding = ENCODE, newline = NEWLINE)
ENCODE =>
'utf_8_sig' # UTF8 BOM付き
'utf_8' # UTF8
NEWLINE =>
'\r\n' # CRLF
'\n' # LF
出力用関数
# 文字列出力 (""で囲む)
def writeStr(value):
return '\"' + str(value) + '\"'
# 数値出力
def writeNum(value):
return str(value)
文字列か否か
# 文字列の場合
if(cell.ctype == xlrd.XL_CELL_TEXT):
writeStr(cell.value)
数値か否か
if(cell.ctype == xlrd.XL_CELL_NUMBER):
if(cell.value.is_integer()):
writeNum(int(cell.value))
# 少数の時 第3位まで
else:
writeNum(round(cell.value, ROUND))
# 許有少数桁
ROUND = 3
整数か否か
value.is_integer()
## 実施方法
python3 tocsv.py