Pythonコーディングの詳細な分析

黄舟
リリース: 2017-07-18 13:27:42
オリジナル
1052 人が閲覧しました

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 つの型のみが保持されます。これについては後ほど説明します。

str と unicode

Python2 は文字列を unicode と str の 2 つのタイプに分割します。本質的に、str はバイナリ バイトのシーケンスです。以下のコード例からわかるように、str 型の「Zen」は 16 進数の xecxf8 として出力され、対応するバイナリ バイト シーケンスは「11101100 11111000」です。

>>> s = '禅'
>>> s
'\xec\xf8'
>>> type(s)
<type &#39;str&#39;>
ログイン後にコピー

Unicode 型 u"Zen" に対応する Unicode シンボルは u'u7985' です

>>> u = u"禅"
>>> u
u&#39;\u7985&#39;
>>> type(u)
<type &#39;unicode&#39;>
ログイン後にコピー

Unicode シンボルをファイルに保存したり、ネットワークに送信したりする場合は、それを str 型に変換する必要がありますエンコード処理を通じて、Python は Unicode から str へ、またはその逆に変換するための encode メソッドを提供します。

encode

>>> u = u"禅"
>>> u
u&#39;\u7985&#39;
>>> u.encode("utf-8")
&#39;\xe7\xa6\x85&#39;
ログイン後にコピー

decode

>>> s = "禅"
>>> s.decode("utf-8")
u&#39;\u7985&#39;
>>>
ログイン後にコピー

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 エラーがどのような場合に発生するかを見てみましょう。

UnicodeEncodeError

Unicode文字列がstrバイト列に変換されるときに発生するUnicode文字列の文字列をファイルに保存する例を見てみましょう

# -*- coding:utf-8 -*-
def main():
    name = u&#39;Python之禅&#39;
    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")
&#39;Python\xe4\xb9\x8b\xe7\xa6\x85&#39;

>>> u"Python之禅".encode("gbk")
&#39;Python\xd6\xae\xec\xf8&#39;
ログイン後にコピー

したがって、Unicode 文字列をファイルに正しく書き込むには、事前に文字列を UTF-8 または GBK エンコードに変換する必要があります。

def main():
    name = u&#39;Python之禅&#39;
    name = name.encode(&#39;utf-8&#39;)
    with open("output.txt", "w") as f:
        f.write(name)
ログイン後にコピー

当然,把 unicode 字符串正确地写入文件不止一种方式,但原理是一样的,这里不再介绍,把字符串写入数据库,传输到网络都是同样的原理

UnicodeDecodeError

UnicodeDecodeError 发生在 str 类型的字节序列解码成 unicode 类型的字符串时

>>> a = u"禅"
>>> a
u&#39;\u7985&#39;
>>> b = a.encode("utf-8")
>>> b
&#39;\xe7\xa6\x85&#39;
>>> b.decode("gbk")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: &#39;gbk&#39; codec can&#39;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: &#39;ascii&#39; codec can&#39;t decode byte 0xe4 in position 0: ordinal not in range(128)
>>>
ログイン後にコピー

str 与 unicode 字符串 执行 + 操作是,Python 会把 str 类型的字节序列隐式地转换成(解码)成 和 x 一样的 unicode 类型,但Python是使用默认的 ascii 编码来转换的,而 ASCII 中不包含中文,所以报错了。

>>> y.decode(&#39;ascii&#39;)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: &#39;ascii&#39; codec can&#39;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&#39;Python\u4e4b\u7985&#39;
ログイン後にコピー

以上内容都是基于 Python2 来讲的,关于 Python3 的字符和编码将会另开一篇文章来写,保持关注。

以上がPythonコーディングの詳細な分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート