PythonでUTF-8ファイルに書き込む


204

私は本当に混乱していcodecs.open functionます。私がする時:

file = codecs.open("temp", "w", "utf-8")
file.write(codecs.BOM_UTF8)
file.close()

それは私にエラーを与えます

UnicodeDecodeError: 'ascii'コーデックは位置0のバイト0xefをデコードできません:序数が範囲(128)にありません

私が行った場合:

file = open("temp", "w")
file.write(codecs.BOM_UTF8)
file.close()

正常に動作します。

質問はなぜ最初の方法が失敗するのですか?そして、どうやってbomを挿入しますか?

2番目の方法がそれを行う正しい方法である場合、使用する意味は何codecs.open(filename, "w", "utf-8")ですか?


54
UTF-8でBOMを使用しないでください。 お願いします。
tchrist

7
@tchristhuh?何故なの?
Salman von Abbas 2013年

8
@SalmanPK BOMはUTF-8では不要であり、複雑さを追加するだけです(たとえば、BOMされたファイルを連結して、有効なテキストで結果を出すことはできません)。このQ&Aを参照してください。Qの下の大きなコメントをお見逃しなく
アロイス・マダル

回答:


271

問題は、それcodecs.BOM_UTF8がUnicode文字列ではなくバイト文字列であると私は考えています。ファイルハンドラーは、「UnicodeをUTF-8でエンコードされたテキストとして書き込むつもりですが、バイトストリングを指定しました!」に基づいて、あなたが本当に意味するところを推測しようとしているのではないかと思います。

バイトオーダーマークのUnicode文字列(つまり、Unicode U + FEFF)を直接書き込んでみて、ファイルがそれをUTF-8としてエンコードするようにします。

import codecs

file = codecs.open("lol", "w", "utf-8")
file.write(u'\ufeff')
file.close()

(それは正しい答えを与えるようです-バイトEF BB BFのファイル)

編集:エンコードはBOMを明示的に記述するよりも優れているため、S。ロットの「utf-8-sig」を使用することをお勧めしますが、以前は問題があったことを説明しているので、ここではこの回答は残しておきます。


警告:オープンとオープンは同じではありません。「コーデックからインポートを開く」を実行する場合、単に「開く」と入力する場合とは異なります。
Apache

2
代わりにcodecs.open( 'test.txt'、 'w'、 'utf-8-sig')を使用することもできます
beta-closed

1
「TypeError:整数が必要です(タイプstrを取得)」と表示されます。ここで何をしているのかわかりません。誰か助けてもらえますか?テキストファイルに文字列(段落)を追加する必要があります。書き込む前に、最初に整数に変換する必要がありますか?
ムゲン

@Mugen:私が書いた正確なコードは、私が見る限り問題なく動作します。取得したコードとエラーの発生場所を正確に示す新しい質問をすることをお勧めします。
Jon Skeet、2018

@Mugenのcodecs.open代わりに呼び出す必要がありますopen
northben

179

以下をお読みください:http : //docs.python.org/library/codecs.html#module-encodings.utf_8_sig

これを行う

with codecs.open("test_output", "w", "utf-8-sig") as temp:
    temp.write("hi mom\n")
    temp.write(u"This has ♭")

結果のファイルは、予想されるBOMを含むUTF-8です。


2
ありがとう。これは機能しました(Windows 7 x64、Python 2.7.5 x64)。このソリューションは、ファイルをモード "a"(追加)で開いたときにうまく機能します。
Mohamad Fakih 2013

これは、Windows上のPython 3では機能しませんでした。代わりに、open(file_name、 'wb')をbomfileとしてこれを行う必要がありました:bomfile.write(codecs.BOM_UTF8)次に、ファイルを再度開いて追加します。
ダスティンアンドリュース

たぶん追加temp.close()
user2905353

2
@ user2905353:必要ありません。これはによって処理されたコンテキスト管理open
matheburg

11

@ S-Lottは正しい手順を提供しますが、Unicodeの問題を拡張して、Pythonインタープリターはより多くの洞察を提供できます。

Jon Skeetはcodecsモジュールについて正しい(珍しい)-バイト文字列が含まれています:

>>> import codecs
>>> codecs.BOM
'\xff\xfe'
>>> codecs.BOM_UTF8
'\xef\xbb\xbf'
>>> 

別のnitを選択すると、BOMは標準のUnicode名を持ち、次のように入力できます。

>>> bom= u"\N{ZERO WIDTH NO-BREAK SPACE}"
>>> bom
u'\ufeff'

次の方法でもアクセスできますunicodedata

>>> import unicodedata
>>> unicodedata.lookup('ZERO WIDTH NO-BREAK SPACE')
u'\ufeff'
>>> 

8

file * nixコマンドを使用して、不明な文字セットファイルをutf-8ファイルに変換します

# -*- encoding: utf-8 -*-

# converting a unknown formatting file in utf-8

import codecs
import commands

file_location = "jumper.sub"
file_encoding = commands.getoutput('file -b --mime-encoding %s' % file_location)

file_stream = codecs.open(file_location, 'r', file_encoding)
file_output = codecs.open(file_location+"b", 'w', 'utf-8')

for l in file_stream:
    file_output.write(l)

file_stream.close()
file_output.close()

1
覚えるのがはるかに簡単な# coding: utf8代わりに 使用# -*- coding: utf-8 -*-します。
show0k
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.