- 前説:CSVの文字コード、utf_8_sig、cp932 などで苦戦
- 同一フォルダ・同一ファイル名:恥ずかしながらのPythonスクリプト(文字コード変更し保管)
- 別フォルダ:恥ずかしながらのPythonスクリプト(現状Pathから別Path置換)
- 余談: shift_jis は cp932 で文字コードを指定した方が良さそう
前説: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付き」書式にすると、文字化けが少なくなるようです。
あ~本来やりたいことの周囲で結構つまづいてます。そろそろ、なんとか、しなくては…と願っています。願うだけでできるなら、ある意味楽かも…と思うボケ爺でした。