ホームページ >バックエンド開発 >Python チュートリアル >Python エンコーディングと Unicode について学ぶ
Unicode と Python についてはたくさんの説明があると思いますが、理解しやすく使いやすくするために、それらについてさらにいくつか書いていくつもりです。
まずはPythonで文字列を定義しましょう。文字列型を使用すると、実際にはバイト文字列が保存されます。
りーこの例では、文字列 abc はバイト文字列です。 97.、98、99 は ASCII コードです。 Python 2.x の定義では、すべての文字列を ASCII として扱います。残念ながら、ASCII はラテン文字セットの中で最も一般的ではない標準です。
ASCII は、文字マッピングに最初の 127 の数字を使用します。 Windows-1252 や UTF-8 などの文字マップは、最初の 127 文字が同じです。文字列内の各バイトの値が 127 未満の場合は、文字列エンコーディングを混合しても安全です。ただし、以下で説明するように、この仮定を行うことには危険があります。
文字列内に 126 を超える値のバイトがある場合、問題が発生します。 Windows-1252 でエンコードされた文字列を見てみましょう。 Windows-1252 の文字マッピングは 8 ビット文字マッピングであるため、合計 256 文字になります。最初の 127 文字は ASCII と同じで、次の 127 文字は Windows-1252 で定義された他の文字です。
りーWindows-1252 はまだバイト文字列ですが、最後のバイトの値が 126 より大きいことがわかりましたか? Python がデフォルトの ASCII 標準を使用してこのバイト ストリームをデコードしようとすると、エラーが報告されます。 Python がこの文字列をデコードすると何が起こるか見てみましょう:
[ a ][ b ][ c ] = "abc" [ 97 ][ 98 ][ 99 ] = "abc"
UTF-8 を使用して別の文字列をエンコードしてみましょう:
A windows-1252 encoded string looks like this: [ 97 ] [ 98 ] [ 99 ] [ 150 ] = "abc–"
よく知っている Unicode エンコーディング テーブルを選択すると、英語のダッシュに対応する Unicode コード ポイントが 8211 (0x2013) であることがわかります。この値は、ASCII の最大値 127 よりも大きくなります。 1バイト以上の値を格納できます。 8211 (0x2013) は 2 バイトであるため、UTF-8 はいくつかのトリックを使用して、1 文字を保存するのに 3 バイト必要であることをシステムに伝える必要があります。 Python がデフォルトの ASCII を使用して、文字値が 126 より大きい UTF-8 でエンコードされた文字列をエンコードする場合を見てみましょう。
りーご覧のとおり、Python はデフォルトで常に ASCII エンコーディングを使用してきました。 4 番目の文字を処理すると、その値が 226 で 126 より大きいため、Python はエラーをスローします。これは混合エンコーディングの問題です。
初めて Python Unicode を学習する場合、デコードという用語が混乱する可能性があります。バイト ストリームを Unicode オブジェクトにデコードしたり、Unicode オブジェクトをバイト ストリームにエンコードしたりできます。
Python は、バイト ストリームを Unicode オブジェクトにデコードする方法を知る必要があります。バイト ストリームを取得したら、その「decode」メソッドを呼び出して、そこから Unicode オブジェクトを作成します。 できるだけ早くバイト ストリームを Unicode にデコードすることをお勧めします。
りーUnicode をバイトストリームにエンコードします
コーデックモジュールの使用
これを試してください:
>>> x = "abc" + chr(150) >>> print repr(x) 'abc\x96' >>> u"Hello" + x Traceback (most recent call last): File "<stdin>", line 1, in ? UnicodeDecodeError: 'ASCII' codec can't decode byte 0x96 in position 3: ordinal not in range(128)
これは Unicode オブジェクトを取得し、それを UTF-8 エンコーディングでファイルに書き込みます。他の状況でも使用できます。
これを試してください:
ファイルからデータを読み取るとき、codecs.open は、UTF-8 でエンコードされたファイルを Unicode オブジェクトに自動的に変換できるファイル オブジェクトを作成します。
上の例を続けてみましょう。今回は urllib ストリームを使用します。
りー単行バージョン:
A UTF-8 encoded string looks like this: [ 97 ] [ 98 ] [ 99 ] [ 226 ] [ 128 ] [ 147 ] = "abc–" [0x61] [0x62] [0x63] [0xe2] [ 0x80] [ 0x93] = "abc-"
コーデック モジュールには細心の注意が必要です。渡すものは Unicode オブジェクトである必要があります。そうでない場合は、バイト ストリームが ASCII として自動的にデコードされます。
りーおっと、Python は再び ASCII を使用してすべてをデコードし始めました。
UTF-8バイトストリームのスライスの問題
次に、次の操作を行います:
>>> x = "abc\xe2\x80\x93" >>> print repr(x) 'abc\xe2\x80\x93' >>> u"Hello" + x Traceback (most recent call last): File "<stdin>", line 1, in ? UnicodeDecodeError: 'ASCII' codec can't decode byte 0xe2 in position 3: ordinal not in range(128)
何? 4 文字のように見えますが、len の結果では 6 文字になっています。 len は文字数ではなくバイト数をカウントするためです。
りーでは、この文字列を分割してみましょう。
りーセグメンテーションの結果は最後のバイトであり、最後の文字ではありません。
UTF-8 を正しくセグメント化するには、バイト ストリームをデコードして Unicode オブジェクトを作成することをお勧めします。そうすれば、安全に操作してカウントできます。
りーPython が自動的にエンコード/デコードする場合
第一个案例是当它试着将Unicode和字节串合并在一起的时候。
>>> u"" + u"\u2019".encode("utf-8") Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 0: ordinal not in range(128)
在合并列表的时候会发生同样的情况。Python在列表里有string和Unicode对象的时候会自动地将字节串解码为Unicode。
>>> ",".join([u"This string\u2019s unicode", u"This string\u2019s utf-8".encode("utf-8")]) Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 11: ordinal not in range(128)
或者当试着格式化一个字节串的时候:
>>> "%s\n%s" % (u"This string\u2019s unicode", u"This string\u2019s utf-8".encode("utf-8"),) Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 11: ordinal not in range(128)
基本上当你把Unicode和字节串混在一起用的时候,就会导致出错。
在这个例子里面,你创建一个utf-8文件,然后往里面添加一些Unicode对象的文本。就会报UnicodeDecodeError错误。
>>> buffer = [] >>> fh = open("utf-8-sample.txt") >>> buffer.append(fh.read()) >>> fh.close() >>> buffer.append(u"This string\u2019s unicode") >>> print repr(buffer) ['This file\xe2\x80\x99s got utf-8 in it\n', u'This string\u2019s unicode'] >>> print "\n".join(buffer) Traceback (most recent call last): File "<stdin>", line 1, in <module> UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 9: ordinal not in range(128)
你可以使用codecs模块把文件作为Unicode加载来解决这个问题。
>>> import codecs >>> buffer = [] >>> fh = open("utf-8-sample.txt", "r", "utf-8") >>> buffer.append(fh.read()) >>> fh.close() >>> print repr(buffer) [u'This file\u2019s got utf-8 in it\n', u'This string\u2019s unicode'] >>> buffer.append(u"This string\u2019s unicode") >>> print "\n".join(buffer) This file’s got utf-8 in it This string’s unicode
正如你看到的,由codecs.open 创建的流在当数据被读取的时候自动地将比特串转化为Unicode。
1.最先解码,最后编码
2.默认使用utf-8编码
3.使用codecs和Unicode对象来简化处理
最先解码意味着无论何时有字节流输入,需要尽早将输入解码为Unicode。这会防止出现len( )和切分utf-8字节流发生问题。
最后编码意味着只有在准备输入的时候才进行编码。这个输出可能是一个文件,一个数据库,一个socket等等。只有在处理完成之后才编码unicode对象。最后编码也意味着,不要让Python为你编码Unicode对象。Python将会使用ASCII编码,你的程序会崩溃。
默认使用UTF-8编码意味着:因为UTF-8可以处理任何Unicode字符,所以你最好用它来替代windows-1252和ASCII。
codecs模块能够让我们在处理诸如文件或socket这样的流的时候能少踩一些坑。如果没有codecs提供的这个工具,你就必须将文件内容读取为字节流,然后将这个字节流解码为Unicode对象。
codecs模块能够让你快速的将字节流转化为Unicode对象,省去很多麻烦。
最后的部分是让你能入门UTF-8,如果你是个超级极客可以无视这一段。
利用UTF-8,任何在127和255之间的字节是特别的。这些字节告诉系统这些字节是多字节序列的一部分。
Our UTF-8 encoded string looks like this: [ 97 ] [ 98 ] [ 99 ] [ 226 ] [ 128 ] [ 147 ] = "abc–"
最后3字节是一个UTF-8多字节序列。如果你把这三个字节里的第一个转化为2进制可以看到以下的结果:
11100010
前3比特告诉系统它开始了一个3字节序列226,128,147。
那么完整的字节序列。
11100010 10000000 10010011
然后你运用三字节序列的下面的掩码。
1110xxxx 10xxxxxx 10xxxxxx XXXX0010 XX000000 XX010011 Remove the X's 0010 000000 010011 Collapse the numbers 00100000 00010011 Get Unicode number 0x2013, 8211 The "–"
这是基本的UTF-8入门,如果想知道更多的细节,可以去看UTF-8的维基页面。
原文链接: ERIC MORITZ 翻译: 伯乐在线 - 贱圣OMG
以上がPython エンコーディングと Unicode について学ぶの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。