pagetakaBlog

最近リフォームと鳥取県日南町の記事多め。写真、PC、ネット等の話題も

Python:CSVの文字コード変更を同一フォルダで実行(VSCode)

前説:CSVの文字コード、utf_8_sig、cp932 などで苦戦

CSV保存する際の文字コードで苦戦したことを少し前の記事に書きました。
pagetaka.hatenablog.jp
東証株式相場表(日報、PDF)をDLし、PDFMinerで解析、CSV(utf_8、BOM無し)がCSVファイルの原状です。これからあとに次のようなことがありました。

  • CSV(utf_8、BOM無し)をExcelで読んだら、列位置ずれ(項目ずれ)が発生
  • CSV(shift_jis)に変換しExcelで読んだら、変換できない文字が「?」に変換
  • CSV(utf_8、BOMあり)に変換し、Excelで読んだら大丈夫だった
  • CSV(utf_8、BOMあり)をMySQLへ読み込ませたら、先頭データ一部欠落
  • CSV(utf_8、BOM無し)をMySQLへ読み込ませたら、大丈夫だった

などイロイロ試してみました。
その過程で、フォルダにある数十のCSVを「Mery」で読込み→エンコード変更→保存、という作業の繰り返しに疲れました。こういうことはPythonにやってもらいたい、ということで、以下のPythonスクリプトを作りましたので、爺の備忘録です。

同一フォルダ・同一ファイル名:恥ずかしながらのPythonスクリプト(文字コード変更し保管)

作業が失敗し、CSVが0KB(名前だけあって中身なし)になるという可能性もあります。CSVを、別フォルダへコピペし万が一(爺のいうことなら十が一…くらいか)に備えるのが良いかと…キッパリ。

#モジュールをインポート
import glob

#指定フォルダ内、全csvの相対path取得(※Python実行環境からの相対位置、ファイル名迄)
in_paths = glob.glob('csv/*.csv')
# encode設定
r_encode = 'utf_8_sig'  #utf8(BOM付き)
w_encode = 'cp932'      #shift_jisとするより同じ意味のcp932で指定した方が変換できない文字が少ないようです

#同一フォルダに同名上書き
for in_path in in_paths:
    out_path = in_path #異なるフォルダに保存時はこの書き方ではNG

    with open(in_path, 'r', encoding=r_encode, errors='replace') as fin:     
        f_txt = fin.read()
        with open(out_path, 'w', encoding=w_encode, errors='replace') as fout:
            fout.write(f_txt)

上の囲みのスクリプト最後の「with」「fout」はインデントがもう一つずつ高くても同様に動いたようです。また、「with」を使っているので「.close()」は使いませんでした。

別フォルダ:恥ずかしながらのPythonスクリプト(現状Pathから別Path置換)

「Path」は、ファイル名を含む状態ですから、あらかじめファイル名の長さを同じにしておくと、別フォルダまたは別名保存などの際には楽かと思います。今回爺がやっている実例は、東証株式相場表の日付(例:20220301)です。なので、Pathは「csv/20220301.csv」となっています。


ということで、文字置換をおこない、別フォルダへ同名で保存。あ~あらかじめ、別フォルダは作っといてくださいね~。今回は「csv」から「cs1」へという例です。失敗例の「replace」、成功例のリスト・スライス、正規表現・subを「print()」で試してみました。

import re #正規表現

#元テキスト
a00 = 'csv/20220301.csv'
print()
print('a00:' + a00 + '←文字数:' + str(len(a00)))

#リストのスライスを使う ※0始まり
a1 = a00[:2]
a2 = a00[3:]
a01 = a1 + '1' +a2
print('a01:' + a01)

#フォルダ名とファイル拡張子が同じでNGとなる例 replace
a11 = a00.replace('csv','cs1')
print('a11:' + a11 + '←NG例')

#正規表現を使って、'CSV'の位置を特定し置換(1)
a21 = re.sub(r'^csv','cs1',a00)   #「^」が先頭を指すのを利用
print('a21:' + a21)

上のスクリプトは単に、現状のPathを、別のPathに書き換えるだけ、それも単に「print()」しているだけです。最初のスクリプトに考え方をを組み合わせると、いともたやすく、別フォルダに同名で文字コードが変更されたCSVが出現する…という、夢のような流れです…。夢よ覚めるな…と爺は寝言を言う…はて。

余談: shift_jis は cp932 で文字コードを指定した方が良さそう

右往左往しながら、encodingで一杯勉強させてもらいました。その結果、爺なりの「教訓」(≒思い込み)が少しばかり。いずれもPythonスクリプトで作業したときです。

  • Excelに読み込ませるときのencodingは「shift_jis」が普通ですが、もともと「utf_8」で作成したファイルを「shift_jis」へ変更するとき、「?」になり変換しきれないものがありました。こういったとき「cp932」を指定すると、その数が劇的に減るようです。
  • Excel、最近は「utf_8」も楽に読み込めるようです。爺が使っているバージョンは「2007」で、ちょっと苦しい状態でした。もし「utf_8」を使うなら「BOM付き」書式にすると、文字化けが少なくなるようです。

あ~本来やりたいことの周囲で結構つまづいてます。そろそろ、なんとか、しなくては…と願っています。願うだけでできるなら、ある意味楽かも…と思うボケ爺でした。