LoginSignup
3
3

【Python】CSVを読み込むと文字列の中に\ufeffが入ってしまう場合の原因と解決方法

Posted at

概要

Djangoで、ユーザーがアップロードしたCSVファイルのヘッダー名が指定のヘッダー名と一致している場合のみアップロードを成功させるという認証方法を実装していました。しかし、ヘッダー名を一致させても頭にBOMの文字列が入っているのが原因で、失敗してしまいました。本記事ではその原因と解決方法を記載します。

エラーが発生したコードと原因

def upload_file(request):
    if request.method == 'POST':
        form = UploadFileForm(request.POST, request.FILES)
        if form.is_valid():
            csvfile = request.FILES['file']
            decoded_file = csvfile.read().decode('utf-8').splitlines()
            reader = csv.reader(decoded_file)
            header = next(reader)

            if header == ['hoge', 'foo']:
            # 省略

上記のコードでCSVをアップロードするとなぜかif分のところで引っかかってしまいます。
おかしいなぁ、と思ってheaderに何が入っているかデバッグしてみました。
すると、以下のように出力されました。

['\ufeffhoge', 'foo']

ん、\ufeffってなんだ?CSV開いても特に頭には何もつけていません...
調べてみると、この\ufeffっていうのは、バイト順マーク、通称BOM(Byte Order Mark)と呼ばれる特殊な文字列とのこと。テキストデータの先頭に配置され、Unicodeエンコーディングを示すために使用されます。テキストの始まりをプログラムに伝える目印みたいなものです。

\ufeffは、ユニコード文字U+FEFFを表し、不可視文字とも呼ばれます。
ということで、解決策はこのBOMを除去することということがわかりました。

BOMについては、Wikipediaにも以下のように記載されています。

プログラムがテキストデータを読み込む時、その先頭の数バイトからそのデータがUnicodeで表現されていること、また符号化形式(エンコーディング)としてどれを使用しているかを判別できるようにしたものである

解決方法

BOMを除去するためには、ファイルを開く際にutf-8-sigのエンコーディングを使用すればOKとのこと。このエンコーディングであれば、BOMを自動的に検出して削除できます。

decoded_file = csvfile.read().decode('utf-8-sig').splitlines() 

上記のように修正したら、BOMが除去され、ヘッダー名も正しく一致されました。
よかったよかった。

参考

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3