1. ホーム
  2. python

[解決済み] PythonでUnicode(UTF-8)のファイル読み書きをする。

2022-03-14 20:54:33

質問

Python 2.4で、ファイルへのテキストの読み書きを理解するのに苦労しています。

# The string, which has an a-acute in it.
ss = u'Capit\xe1n'
ss8 = ss.encode('utf8')
repr(ss), repr(ss8)

("u'Capitxe1n'", "'Capitxc3xa1n'")

print ss, ss8
print >> open('f1','w'), ss8

>>> file('f1').read()
'Capit\xc3\xa1n\n'

で、入力するのは Capit\xc3\xa1n をお気に入りのエディタで、ファイル f2 に書き込んでください。

では

>>> open('f1').read()
'Capit\xc3\xa1n\n'
>>> open('f2').read()
'Capit\\xc3\\xa1n\n'
>>> open('f1').read().decode('utf8')
u'Capit\xe1n\n'
>>> open('f2').read().decode('utf8')
u'Capit\\xc3\\xa1n\n'

私はここで何を理解していないのだろうか?明らかに私が見逃している重要な魔法(または良識)があるのです。テキストファイルに何を入力すれば、適切な変換ができるのでしょうか?

私がここで本当に理解できていないのは、Pythonが外部からUTF-8を認識できないのであれば、UTF-8表現のポイントは何なのか、ということです。文字列をJSONダンプして、代わりにそれを使うべきかもしれませんね。もっと重要なのは、ファイルから入ってきたときにPythonが認識してデコードする、このUnicodeオブジェクトのASCII表現はあるのでしょうか? もしそうなら、どうやってそれを手に入れるのですか?

>>> print simplejson.dumps(ss)
'"Capit\u00e1n"'
>>> print >> file('f3','w'), simplejson.dumps(ss)
>>> simplejson.load(open('f3'))
u'Capit\xe1n'

解決方法は?

表記法では

u'Capit\xe1n\n'

は1バイトを表し、quot;e1;は16進数であることを表しています。 と書くと

Capit\xc3\xa1n

の中に、" \xc3" が入っていますね。これは4バイトで、コードの中では全部読んでいます。表示させるとわかると思います。

>>> open('f2').read()
'Capit\\xc3\\xa1n\n'

バックスラッシュでエスケープされているのがわかると思います。つまり、文字列には "\", "x", "c", "3" の4バイトが含まれることになります。

編集してください。

他の方の回答にもあるように、エディタに文字を入力すれば、エディタがUTF-8に変換して保存してくれるはずです。

実際にこの形式の文字列がある場合は string_escape コーデックで通常の文字列にデコードします。

In [15]: print 'Capit\\xc3\\xa1n\n'.decode('string_escape')
Capitán

その結果、UTF-8でエンコードされた文字列となり、アクセント記号付きの文字は、次の2バイトで表されます。 \\xc3\\xa1 を元の文字列に追加します。ユニコード文字列にしたい場合は、再度UTF-8でデコードする必要があります。

編集へ:あなたのファイルにはUTF-8がありません。実際にどのように見えるかを見るには

s = u'Capit\xe1n\n'
sutf8 = s.encode('UTF-8')
open('utf-8.out', 'w').write(sutf8)

ファイルの内容を比較する utf-8.out を、エディタで保存したファイルの内容と比較します。