こんにちは、Token_w のブログです。ようこそ。
今日の記事では Python の文字列と文字エンコーディングについて説明します。基礎的な理論的知識と実践的な応用が含まれています。お役に立てば幸いです。お役に立てば幸いです
。いいねやコレクションのサポートを獲得してください。ありがたい
目次
I.はじめに
Python の文字エンコーディングは昔ながらのトピックであり、同僚がこの点に関して多くの記事を書いています。他人の言葉をそのまま反映する人もいれば、深く書く人もいます。最近、有名な研修機関の教育ビデオでこの問題が再び議論されているのを見たが、まだ納得のいく説明ではなかったので、この文章を書きたいと思った。一方では関連する知識を整理し、他方では他の人に役立つことを願っています。
Python2 のデフォルトのエンコーディングはASCII で、中国語の文字を認識できないため、明示的に指定する必要があります。Python3のデフォルトのエンコーディングは、中国語の文字を認識できる Unicode です。
皆さんも上記と同様の「Pythonによる中国語処理」の説明を多くの記事でご覧になったことがあると思いますが、このような説明を初めて見たときはよく理解できたと思います。しかし、長い時間が経って、関連する問題に繰り返し遭遇すると、自分の理解がそれほど明確ではないと感じるようになります。上記のデフォルトのエンコーディングの役割を理解すると、その文の意味がより明確に理解できるようになります。
2. 関連概念
2.1 文字とバイト
文字はバイトと等価ではありません。文字は人間が認識できる記号であり、これらの記号をコンピューターのストレージに保存するには、コンピューターが認識できるバイトで表す必要があります。多くの場合、1 つの文字には複数の表現方法があり、表現方法が異なれば使用されるバイト数も異なります。ここで説明するさまざまな表現方法は文字エンコーディングを指します。たとえば、文字 A~Z は ASCII コード (1 バイトを占有する) で表現することも、UNICODE (2 バイトを占有する) で表現することも、UTF-8 で表現することもできます。 ( は 1 バイトを占めます)。文字エンコーディングの役割は、人間が認識できる文字を機械が認識できるバイトコードに、またはその逆に変換することです。
UNICDOE は実際の文字列であり、ASCII、UTF-8、GBK などの文字コードはバイト列を表します。この点については、Pythonの公式ドキュメントの「Unicode文字列」で「Unicode文字列をバイト列に変換する」といった記述がよく見られます。
私たちはファイルにコードを記述し、文字はバイト単位でファイルに格納されるため、ファイルに文字列を定義するとバイト文字列として扱われることは理解できます。ただし、必要なのは文字列であり、バイト文字列ではありません。優れたプログラミング言語は、この 2 つの関係を厳密に区別し、独創的かつ完璧なサポートを提供する必要があります。JAVA 言語は非常に優れているため、Python と PHP について学ぶ前は、プログラマーが扱うべきではないこれらの問題について考えたこともありませんでした。残念なことに、多くのプログラミング言語は「文字列」と「バイト列」を混同しようとしており、バイト列を文字列として使用していますが、PHP や Python2 もこのプログラミング言語に属します。この問題を最もよく説明する操作は、中国語の文字を含む文字列の長さを取得することです。
- 文字列の長さを取得すると、結果は中国語か英語に関係なく、すべての文字列の数になります。
- 文字列に対応するバイト列の長さは、エンコード (エンコード) プロセスで使用される文字エンコーディングに関連します (例: UTF-8 エンコーディングでは、中国語の文字は 3 バイトで表現する必要があります。GBK エンコーディングでは、中国語の文字を表す必要があります)。表現するには 2 バイトが必要です)
注: Windows cmd ターミナルのデフォルトの文字エンコーディングは GBK であるため、cmd に入力された中国語の文字は 2 バイトで表現される必要があります
# Python2
a = 'Hello,中国' # 字节串,长度为字节个数 = len('Hello,')+len('中国') = 6+2*2 = 10
b = u'Hello,中国' # 字符串,长度为字符个数 = len('Hello,')+len('中国') = 6+2 = 8
c = unicode(a, 'gbk') # 其实b的定义方式是c定义方式的简写,都是将一个GBK编码的字节串解码(decode)为一个Uniocde字符串
print(type(a), len(a))
# (<type 'str'>, 10)
print(type(b), len(b))
# (<type 'unicode'>, 8)
print(type(c), len(c))
# (<type 'unicode'>, 8)
Python 3 では文字列のサポートが大きく変更されましたので、その詳細を以下に紹介します。
2.2 エンコードとデコード
まず、一般的な科学について説明します。UNICODE 文字エンコーディングも文字と数値の間のマッピングですが、ここでの数値はコード ポイントと呼ばれ、実際には 16 進数です。
Python の公式ドキュメントでは、Unicode 文字列、バイト文字列、エンコーディングの関係について説明しています。
Unicode 文字列はコード ポイント (コード ポイント) のシーケンスであり、コード ポイントの範囲は 0 から 0x10FFFF (10 進数の 1114111 に相当) です。このコード ポイントのシーケンスは、ストレージ (メモリや物理ディスクを含む) 内でバイトのセット (0 ~ 255 の値) として表現される必要があり、Unicode 文字列をバイトのシーケンスに変換するための規則はエンコーディングと呼ばれます。
ここで言及するエンコーディングは文字エンコーディングを指すのではなく、エンコーディング プロセスと、このプロセスで使用されるUnicode 文字のコード ポイントとバイト間のマッピング ルールを指します。このマッピングは単純な 1 対 1 マッピングである必要はないため、エンコード プロセスで考えられるすべての Unicode 文字を処理する必要はありません。次に例を示します。
Unicode 文字列を ASCII エンコードに変換するためのルールは、コード ポイントごとに次のように簡単です。
-
コード ポイント値が 128 未満の場合、各バイトはコード ポイントと同じ値になります。
-
コード ポイント値 >= 128 の場合、Unicode 文字列はこのエンコーディングでは表現できません (この場合、Python は UnicodeEncodeError 例外を発生させます)。Unicode 文字列を
UTF-8 エンコーディングに変換するには、次のルールが使用されます。 -
コードポイント値が 128 未満の場合、対応するバイト値で表されます (Unicode から ASCII バイトへの変換と同じ)。
-
コード ポイント値が 128 以上の場合、2 バイト、3 バイト、または 4 バイトのシーケンスに変換され、シーケンス内の各バイトは 128 ~ 255 になります。
簡単な要約: -
エンコーディング (encode) : Unicode 文字列 (コード ポイント) を特定の文字エンコーディングに対応するバイト文字列に変換するプロセスとルール
-
デコード (decode) : 特定の文字エンコーディングのバイト列を、対応する Unicode 文字列 (その中のコードポイント) に変換するプロセスと規則。
エンコードでもデコードでも、重要な要素が必要であることがわかります。特定の文字エンコーディング。文字は異なる文字エンコーディングでエンコードされるため、ほとんどの場合、バイト値とバイト数は異なり、またその逆も同様です。
3. Python のデフォルトのエンコーディング
3.1 Pythonソースコードファイルの実行処理
ディスク上のファイルはバイナリ形式で保存され、テキスト ファイルはすべて特定のエンコーディングのバイト形式で保存されていることは誰もが知っています。プログラムのソースコードファイルの文字エンコードはエディタで指定しますが、例えばPycharmを使ってPythonのプログラムを書く場合、プロジェクトのエンコードとファイルのエンコードをUTF-8に指定すると、Pythonのコードは次のように変換されます。ディスクに保存するときは UTF -8 は、対応するバイトをエンコード (エンコード プロセス) してディスクに書き込みます。Python コード ファイル内のコードを実行する場合、Python インタプリタは Python コード ファイル内のバイト列を読み取った後、後続の操作を実行する前にそれを UNICODE 文字列に変換する (デコード処理) 必要があります。
上で説明したように、この変換プロセス (デコード、デコード) では、ファイルに保存されたバイトで使用される文字エンコーディングを指定する必要があります。これにより、これらのバイトが UNICODE Universal Code および Unicode で対応するコード ポイントを見つけることができることがわかります。それは...ですか。ここで文字エンコーディングを指定する方法は、次のように誰もがよく知っています。
# -*- coding:utf-8 -*-
3.2 デフォルトのエンコーディング
では、コード ファイルの先頭で文字エンコーディングを指定しない場合、Python インタプリタはコード ファイルから読み取ったバイトを UNICODE コード ポイントに変換するためにどの文字エンコーディングを使用するのでしょうか? ソフトウェアを構成するときと同様に、デフォルトのオプションが多数あります。この問題を解決するには、Python インタプリタ内でデフォルトの文字エンコーディングを設定する必要があります。これが、記事の冒頭で述べた「デフォルトのエンコーディング」です。したがって、誰もが言った Python の漢字の問題は、一文で要約できます。デフォルトの文字エンコーディングでバイトを変換できない場合、デコード エラー (UnicodeEncodeError) が発生します。
Python2 と Python3 インタープリターで使用されるデフォルトのエンコーディングは異なります。デフォルトのエンコーディングは sys.getdefaultencoding() を通じて取得できます。
# Python2
import sys
print(sys.getdefaultencoding() )
# 'ascii'
# Python3
import sys
print(sys.getdefaultencoding() )
# 'utf-8'
したがって、Python2 の場合、Python インタプリタが中国語の文字のバイトコードを読み取って操作をデコードしようとすると、まず、現在のコード ファイルのヘッダーが、現在のコード ファイルに格納されているバイトコードに対応する文字エンコーディングが示されているかどうかを確認します。何。指定しない場合、デフォルトの文字エンコーディング「ASCII」がデコードに使用され、デコードが失敗し、次のエラーが発生します。
SyntaxError: Non-ASCII character '\xc4' in file xxx.py on line 11, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details
Python3 の場合も、実行プロセスは同じですが、Python3 インタープリターはデフォルトのエンコーディングとして「UTF-8」を使用しますが、これは中国語の問題と完全に互換性があることを意味するわけではありません。たとえば、Windows で開発する場合、Python プロジェクトとコード ファイルはデフォルトの GBK エンコーディングを使用します。これは、Python コード ファイルが GBK 形式のバイトコードに変換されてディスクに保存されることを意味します。Python3 のインタープリターがコード ファイルを実行するときに、UTF-8 でデコードしようとすると、デコードも失敗し、次のエラーが発生します。
SyntaxError: Non-UTF-8 code starting with '\xc4' in file xxx.py on line 11, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details
3.3 ベストプラクティス
- プロジェクトを作成したら、まずプロジェクトの文字コードがUTF-8になっているか確認してください。
- Python2 および Python3 と互換性を持たせるには、コード ヘッダーで文字エンコーディングを宣言します: - -coding:utf-8 - -
4. Python2 および Python3 での文字列のサポート
実際、Python3 での文字列サポートの改善は、デフォルトのエンコーディングを変更するだけでなく、文字列を再実装することであり、UNICODE の組み込みサポートを実現しています。この観点から見ると、Python は優れています。ジャワ。Python2 と Python3 での文字列のサポートの違いを見てみましょう。
(1) Python2
Python2 の文字列のサポートは、次の 3 つのクラスによって提供されます。
class basestring(object)
class str(basestring)
class unicode(basestring)
help(str) と help(bytes) を実行すると、結果が str クラスの定義であることがわかります。これは、Python2 の str がバイト文字列であり、後続の Unicode オブジェクトが実際の文字列に対応していることも示しています。
#!/usr/bin/env python
# -*- coding:utf-8 -*-
a = '你好'
b = u'你好'
print(type(a), len(a))
print(type(b), len(b))
出力結果:
(<type 'str'>, 6)
(<type 'unicode'>, 2)
(2) Python3
Python3 での文字列のサポートは実装クラスのレベルで簡素化され、unicode クラスが削除され、bytes クラスが追加されました。表面的には、Python3 の str と unicode が 1 つに統合されたと考えることができます。
class bytes(object)
class str(object)
実際、Python3 は以前の間違いに気づき、文字列とバイトを明確に区別し始めました。したがって、Python3 の str はすでに実際の文字列であり、バイトは別のバイト クラスで表されます。つまり、Python3 ではデフォルトで文字列が定義されているため、UNICODE の組み込みサポートが実現され、プログラマの文字列処理の負担が軽減されます。
#!/usr/bin/env python
# -*- coding:utf-8 -*-
a = '你好'
b = u'你好'
c = '你好'.encode('gbk')
print(type(a), len(a))
print(type(b), len(b))
print(type(c), len(c))
出力結果:
<class 'str'> 2
<class 'str'> 2
<class 'bytes'> 4
5. 文字コード変換
上で述べたように、図に示すように、UNICODE 文字列は任意の文字エンコーディングのバイトに変換できます。
次に、誰もが簡単に疑問を思いつくでしょう。それは、異なる文字エンコーディングのバイトを Unicode を介して相互に変換できるかということです。 ? 答えは「はい」です。
Python2における文字列の文字エンコード変換処理は、
バイト文字列 –> デコード(「元の文字エンコード」) –> Unicode文字列 –> エンコード(「新しい文字エンコード」) –> バイト文字列
#!/usr/bin/env python
# -*- coding:utf-8 -*-
utf_8_a = '我爱中国'
gbk_a = utf_8_a.decode('utf-8').encode('gbk')
print(gbk_a.decode('gbk'))
出力結果:
我爱中国
Python3 で定義された文字列はデフォルトで Unicode であるため、最初にデコードする必要はなく、次のように新しい文字エンコーディングに直接エンコードできます。
string –> encode('新しい文字エンコーディング') –> バイト文字列
#!/usr/bin/env python
# -*- coding:utf-8 -*-
utf_8_a = '我爱中国'
gbk_a = utf_8_a.encode('gbk')
print(gbk_a.decode('gbk'))
出力結果:
私は中国が大好きです
最後に説明しておきたいのは、Unicode は Youdao 辞書でも Google 翻訳機でもありません。中国語を英語に翻訳することはできません。正しい文字エンコーディング変換プロセスでは、同じ文字のバイト表現のみが変更されますが、文字自体のシンボルは変更されるべきではないため、文字エンコーディング間のすべての変換が意味を持つわけではありません。この文をどう理解すればいいでしょうか?たとえば、GBK でエンコードされた「中国」は UTF-8 文字エンコードに変換された後、4 バイトから 6 バイトで表されるだけですが、その文字表現は「Hello」や「China」ではなく「China」のままである必要があります。 。
多くの紙面を割いて概念と理論を紹介し、後半で実践に焦点を当てました。お役に立てば幸いです。
付録 6. 文字エンコーディング
1.ASCIIコード
ASCII コードは、米国によって開発された初期のエンコード仕様であり、英語文字、アラビア数字、欧文文字、および 32 個の制御文字を含む 128 文字しか表現できません。簡単に言うと以下の表になります。
2. 拡張ASCIIコード(Extended ASCII)
簡単に言えば、拡張 ASCII コードの登場は、ASCII では不十分であるため、ASCII テーブルは 256 シンボルまで拡張され続けています。しかし、拡張 ASCII のため、国ごとに規格が異なり、それが Unicode エンコーディングの誕生を促しました。拡張 ASCII コード テーブルは次のとおりです。
3. ユニコード
正確に言うと、Unicode はエンコード形式ではなく、文字セットです。この文字セットには、世界中の現在のシンボルがすべて含まれています。また、本来は1バイト、つまり8ビットで表現できる文字もありましたが、Unicodeではすべての文字の長さが16ビットに統一されているため、文字は固定長となります。Unicode は次のようになります。
\u4f60\u597d\u4e2d\u56fd\uff01\u0068\u0065\u006c\u006c\u006f\uff0c\u0031\u0032\u0033
上記の Unicode は「Hello China! hello, 123」を意味します。
Unicode については、すべての文字が次の Web サイトで確認できます: https://unicode-table.com/en/
4.GB2312
中国人がコンピュータを入手するとき、中国語の文字をエンコードする必要があります。ASCII コード表に基づくと、127 未満の文字の意味は元の文字と同じで、127 より大きい 2 バイトを連結して漢字を表します。前のバイトは 0xA1 (161) から 0xF7 ( 247)の1バイトを上位バイト、後半の0xA1(161)から0xFE(254)までの94バイトを下位バイトと呼び、両者を組み合わせると約8000通りの組み合わせが可能であり、使用されます。 6763 の簡体字、数学記号、ローマ字、日本語文字などを表現します。再コード化された数字、句読点、文字は 2 バイト長のコードであり、これを「全角」文字と呼び、ASCII コード表の 127 より下の元の文字を「半角」文字と呼びます。簡単に言えば、GB2312 は ASCII に基づく簡体字中国語文字の拡張です。
GB2312 コード表: http://www.fileformat.info/info/charset/GB2312/list.htm
5.GBK
簡単に言うと、GBK は GB2312 をさらに拡張したものです (K は中国語のピンイン kuo Zhan (拡張) の「拡張」という単語の最初の子音で、GB2312 と完全な互換性のある 21886 個の中国語の文字と記号が含まれています。
6. GB18030
GB18030 には 70244 個の漢字が含まれており、より包括的で GB 2312-1980 および GBK と互換性があります。GB18030 は少数民族の中国語文字をサポートしており、繁体字中国語文字、日本語および韓国語の中国語文字も含まれています。そのエンコーディングは、シングル、ダブル、4 バイトの可変長エンコーディングです。
7. UTF(UCS転送フォーマット)
UTF は、インターネット上で最も広く使用されている Unicode の実装です。最も一般的に使用されるのは UTF-8 (データが一度に 8 ビットずつ送信されることを意味します) ですが、このほかに UTF-16 もあります。
UTF-8 は次のようになります。「Hello China! hello, 123」:
こんにちは中国!こんにちは、123
8. 簡単な概要
- 中国人は中国語の ASCII コードを拡張および変換して、一般的に使用される 6,000 以上の漢字を表現できる GB2312 コードを作成しました。
- 繁体字やさまざまな文字を含む中国語の文字が多すぎるため、GB2312 のエンコーディングを組み込み、同時に大幅に拡張した GBK エンコーディングが作成されました。
- 中国は多民族国家であり、各国は独自の独立した言語体系を持っており、それらの文字を表現するために GBK コードを GB18030 コードに拡張し続けています。
- 中国など、各国はそれぞれ独自の言語をコード化しているため、さまざまなコードが登場しますが、対応するコードをインストールしないと、対応するコードが何を表現したいのかを説明することができません。
- ついにISOという組織が我慢できなくなった。彼らは協力して、UNICODE と呼ばれるコードを作成しました。このコードは、世界中のあらゆる文字やロゴを収容できるほど大きいものです。したがって、コンピュータが UNICODE エンコード システムを備えている限り、世界にどのような種類のテキストが存在しても、ファイルを UNICODE エンコードで保存するだけでよく、他のコンピュータでも正常に解釈できます。
- UNICODE のネットワーク伝送では、UTF-8 と UTF-16 の 2 つの規格が登場し、それぞれ 8 ビットと 16 ビットの伝送が行われました。UTF-8 では非常に多くの文字や記号を保存できるのに、なぜ中国では GBK やその他のエンコーディングを使用する人が非常に多いのかと疑問に思う人もいるでしょう。UTF-8 およびその他のエンコーディングはサイズが比較的大きく、多くのコンピューター領域を占有するため、ユーザーのほとんどが中国人の場合は、GBK およびその他のエンコーディングも使用できます。