Python を開発する人は皆、文字エンコーディングの問題に困惑していると言われています。最も一般的なエラーは UnicodeEncodeError と UnicodeDecodeError です。残念なことに、このエラーは他の場所でも発生し、問題は常に繰り返されます。 str を Unicode に変換するのに decode メソッドを使用するか、encode メソッドを使用するかを思い出すのが難しく、何が問題なのでしょうか。
この問題を明確にするために、Pythonの文字列の構成や文字エンコードの詳細から徹底的に分析することにしました
コンピュータに保存されているすべてのデータ、テキスト文字、写真、ビデオ、オーディオ、ソフトウェア これらはすべて 01 のバイト列で構成されており、1 バイトは 8 ビットに相当します。
文字は記号です。たとえば、漢字、英字、数字、句読点などはすべて文字と呼ばれます。
バイトは保存やネットワーク送信に便利で、文字は表示に使用され読みやすいです。たとえば、文字「p」はバイナリデータの文字列01110000
としてハードディスクに保存されており、長さは1バイトを占めます
エディタでテキストを開くと、各文字が表示され、最終的にディスクに保存されるときは、バイナリ バイト シーケンスの形式で保存されます。文字からバイトへの変換プロセスはエンコーディングと呼ばれ、その逆はデコーディングと呼ばれます。この 2 つは可逆プロセスです。エンコードは保存と送信を目的とし、デコードは表示と読み取りを目的としています。
たとえば、文字「p」はエンコードされ、バイナリバイト 01110000 のシーケンスとしてハードディスクに保存され、長さは 1 バイトになります。文字「Zen」は、「11100111 10100110 10000101」として 3 バイトの長さを占めることができます。なぜそれが可能ですか?これについては後で説明します。
なぜ Python コーディングはこんなに苦痛なのでしょうか?もちろん、これを開発者のせいにすることはできません。
これは、Python2 がデフォルトのエンコーディングとして ASCII 文字エンコーディングを使用しており、ASCII では中国語を処理できないためです。そのため、なぜ UTf-8 を使用しないのでしょうか?なぜなら、Guido お父さんが Python の最初のコード行を書いたのは 1989 年の冬で、最初のバージョンは 1991 年 2 月に正式にオープンソース化されてリリースされ、Unicode は 1991 年 10 月にリリースされました。つまり、Python という言語が作成されたことになります。 8人はまだ生まれていなかったので、これはそのうちの1人でした。
Python は文字列の型を unicode と str の 2 つの型に分けているため、開発者が混乱しています。これが 2 番目の理由です。 Python3 では文字列が完全に再構成され、1 つの型のみが保持されます。これについては後ほど説明します。
Python2 は文字列を unicode と str の 2 つのタイプに分割します。本質的に、str はバイナリ バイトのシーケンスです。以下のコード例からわかるように、str 型の「Zen」は 16 進数の xecxf8 として出力され、対応するバイナリ バイト シーケンスは「11101100 11111000」です。
>>> s = '禅' >>> s '\xec\xf8' >>> type(s) <type 'str'>
Unicode 型 u"Zen" に対応する Unicode シンボルは u'u7985' です
>>> u = u"禅" >>> u u'\u7985' >>> type(u) <type 'unicode'>
Unicode シンボルをファイルに保存したり、ネットワークに送信したりする場合は、それを str 型に変換する必要がありますエンコード処理を通じて、Python は Unicode から str へ、またはその逆に変換するための encode メソッドを提供します。
encode
>>> u = u"禅" >>> u u'\u7985' >>> u.encode("utf-8") '\xe7\xa6\x85'
decode
>>> s = "禅" >>> s.decode("utf-8") u'\u7985' >>>
str は実際にはバイナリ データの文字列であり、Unicode は文字であることを覚えていれば、多くの初心者は str と unicode 間の変換に encode と decode のどちらを使用するかを思い出せません。 (シンボル) であり、エンコードは文字 (シンボル) をバイナリ データに変換するプロセスであるため、unicode から str への変換には encode メソッドが必要であり、その逆に decode メソッドが必要です。
encoding always takes a Unicode string and returns a bytes sequence, and decoding always takes a bytes sequence and returns a Unicode string”.
str と unicode の変換関係を明確にした後、UnicodeEncodeError と UnicodeDecodeError エラーがどのような場合に発生するかを見てみましょう。
Unicode文字列がstrバイト列に変換されるときに発生するUnicode文字列の文字列をファイルに保存する例を見てみましょう
# -*- coding:utf-8 -*- def main(): name = u'Python之禅' f = open("output.txt", "w") f.write(name)
エラーログ
UnicodeEncodeError: ‘ascii’ codec can’t encode characters in position 6-7: ordinal not in range(128)
なぜUnicodeEncodeErrorが発生するのでしょうか?
write メソッドを呼び出すと、Python は最初に文字列の型を判断します。str 型の文字列自体はバイナリ バイト シーケンスであるため、文字列はエンコードされずに直接ファイルに書き込まれます。
文字列が Unicode 型の場合、まず encode メソッドを呼び出して Unicode 文字列をバイナリ str 型に変換してから、それをファイルに保存します。encode メソッドは Python のデフォルトの ASCII コードを使用してエンコードします
以下と同等です。
>>> u"Python之禅".encode("ascii")
ただし、ASCII 文字セットには中国語を除く 128 のラテン文字しか含まれていないことがわかっているため、「ascii」コーデックでは文字をエンコードできないというエラーが発生します。エンコードを正しく使用するには、UTF-8、GBK などの中国語の文字を含む文字セットを指定する必要があります。
>>> u"Python之禅".encode("utf-8") 'Python\xe4\xb9\x8b\xe7\xa6\x85' >>> u"Python之禅".encode("gbk") 'Python\xd6\xae\xec\xf8'
したがって、Unicode 文字列をファイルに正しく書き込むには、事前に文字列を UTF-8 または GBK エンコードに変換する必要があります。
def main(): name = u'Python之禅' name = name.encode('utf-8') with open("output.txt", "w") as f: f.write(name)
当然,把 unicode 字符串正确地写入文件不止一种方式,但原理是一样的,这里不再介绍,把字符串写入数据库,传输到网络都是同样的原理
UnicodeDecodeError 发生在 str 类型的字节序列解码成 unicode 类型的字符串时
>>> a = u"禅" >>> a u'\u7985' >>> b = a.encode("utf-8") >>> b '\xe7\xa6\x85' >>> b.decode("gbk") Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeDecodeError: 'gbk' codec can't decode byte 0x85 in position 2: incomplete multibyte sequence
把一个经过 UTF-8 编码后生成的字节序列 ‘\xe7\xa6\x85′ 再用 GBK 解码转换成 unicode 字符串时,出现 UnicodeDecodeError,因为 (对于中文字符)GBK 编码只占用两个字节,而 UTF-8 占用3个字节,用 GBK 转换时,还多出一个字节,因此它没法解析。避免 UnicodeDecodeError 的关键是保持 编码和解码时用的编码类型一致。
这也回答了文章开头说的字符 “禅”,保存到文件中有可能占3个字节,有可能占2个字节,具体处决于 encode 的时候指定的编码格式是什么。
再举一个 UnicodeDecodeError 的例子
>>> x = u"Python" >>> y = "之禅" >>> x + y Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128) >>>
str 与 unicode 字符串 执行 + 操作是,Python 会把 str 类型的字节序列隐式地转换成(解码)成 和 x 一样的 unicode 类型,但Python是使用默认的 ascii 编码来转换的,而 ASCII 中不包含中文,所以报错了。
>>> y.decode('ascii') Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)
正确地方式应该是显示地把 y 用 UTF-8 或者 GBK 进行解码。
>>> x = u"Python" >>> y = "之禅" >>> y = y.decode("utf-8") >>> x + y u'Python\u4e4b\u7985'
以上内容都是基于 Python2 来讲的,关于 Python3 的字符和编码将会另开一篇文章来写,保持关注。
以上がPythonコーディングの詳細な分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。