☆☆ 新着記事 ☆☆

2019年2月5日火曜日

UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8e in position 87: invalid start byte

PythonでCSVファイルを読み込むとき、以下のようなエラーコードが出ることがある。
特に、windowsのexcelでcsvが作成されていたりすると、エンコードが問題になることが良くあります。

このポストでは、この問題に対応する仕方をメモしておきます。。

1. 文字エンコードの復習。

*ASCII -- 最も基本的な文字コード。 半角英数字128文字から構成されており、全ての文字を1バイトで表します。例えば、「A」は、0x41(0xは16進数を表す。)

*UTF-8 -- 全ての文字を1~4バイトで表します。 世界中の文字を扱えるために、標準的に使われるようになりました。 Pythonの基本のエンコードになります。 UTF-8には、「バイト・オーダー・マーク(BOM)」の有無のオプションがあります。 (Excel形式を保持したい場合、「BOMあり」になります。) 
Pythonで標準のcsvモジュールで、BOMありのUTF-8を読む場合は 、open()関数に encoding='utf_8_sig' と指定します。すると、最初の文字が '\ufeff ' になります。

逆にBOMなしUTF-8を指定して読むと、普通に読めて問題ありません。

*Shift-JIS -- パソコンで利用された日本語の文字コード。 全ての文字を2バイトで表します。

*Code Page932(cp932) -- Windows環境の日本語の文字コード。Shift-JISの一つのバリエーション。

2. CSVファイルのエンコードの判定
open()関数に、開きたいcsvが利用しているエンコードを指定しなくてはいけないので、どの文字コードを利用しているか判定するツール。

1) cardet を利用する。
(https://pypi.org/project/chardet/ )

これで判別できるのは、

  • ASCII, UTF-8, UTF-16 (2 variants), UTF-32 (4 variants)
  • Big5, GB2312, EUC-TW, HZ-GB-2312, ISO-2022-CN (Traditional and Simplified Chinese)
  • EUC-JP, SHIFT_JIS, CP932, ISO-2022-JP (Japanese)
  • EUC-KR, ISO-2022-KR (Korean)
  • KOI8-R, MacCyrillic, IBM855, IBM866, ISO-8859-5, windows-1251 (Cyrillic)
  • ISO-8859-5, windows-1251 (Bulgarian)
  • ISO-8859-1, windows-1252 (Western European languages)
  • ISO-8859-7, windows-1253 (Greek)
  • ISO-8859-8, windows-1255 (Visual and Logical Hebrew)
  • TIS-620 (Thai)
  • だそうです。

    2)自作のモジュールを利用する(未検証。 メモです。)
      
    *getencモジュールのgetenc.getEncode()でファイルの文字コードの判別を行って、その文字コードをopen関数の引数として指定する。

    enc = getenc.getEncode ('anycsvfilename.csv')
    with open ('anycsvfilename.csv','r', encoding=en) as f:

    など。

    関数自身は、
    http://myfuturesightforpast.blogspot.jp/2015/01/auto-detecting-japanese-file-encoding.html
    参照。

    3)Linuxサーバー上のコマンドで確認
    > file -i [ファイル名]

    # file -i 増減率一覧.csv
    増減率一覧.csv: text/plain; charset=unknown-8bit ・・読み込めないファイル

    # file -i prefectures.csv
    prefectures.csv: text/plain; charset=utf-8

    3. エラー対処

    エラー表示
    UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8e in position xx: invalid start byte
    (0x8e: EUC_JPで使われる制御文字?)

    ① CSVを以下の読み込みの記述にする。

    with open("myanyfilename.csv","r",newline='',encoding='utf_8') as f:
          csv_reader=csv.DictReader(f)

    *Python3.7 で、上記で読み込もうとした際のエラーメッセージ。
    encoding='EUC_JP' とすると読める。


    UnicodeDecodeError: 'cp932' codec can't decode byte 0xef in position 0: illegal multibyte sequence
    ① 以下のencoding用の記述で対処。

    with open("start.csv","r", encoding='utf-8_sig') as f:  #windows encoding用の記述

    但し、(windows環境でutf-8にファイル自体を変えておかないと、この記述をしても、読み込みエラーになる場合もある。)

    又、1つのファイルに複数のエンコード文字が入っていると、これだけで対処は難しい。


    4.究極の対応。

    Editorで、csvファイルを開いて、utf_8 フォーマットで保存する。

    Excelだと、「csv(コンマ区切り)で保存。」だと、エンコードを変換してくれないが、
    新しいExcel(少なくてもOffice365)では、、「csv utf-8 (コンマ区切り)で保存。」すれば、エンコードを変更してくれる。

    csvのサイズも大きくないので、これで、今のところ正しく読みこみできるようになる。
    いちいち、open関数の引数で、各々のエンコードを指定しなくても良いので、便利ではある。

    自分で、Python csvモジュールでcsvを作成する場合、encoding='utf-8' を指定して書き込めば、
    大丈夫。

    以上 :)

    0 件のコメント:

    コメントを投稿