このようなエンコーディングの問題の鍵は、原則として 「string」は2つの異なる概念の(1)文字列:文字、及び(2)ストリング/アレイバイト。256文字以下のエンコーディング(ASCII、Latin-1、Windows-1252、Mac OS Romanなど)の歴史的な偏在のため、この区別はほとんど長い間無視されてきました。これらのエンコーディングは、一連の一般的な文字を0〜255(バイト)の数値。ほとんどのプログラムは、同じオペレーティングシステムに残っているテキストを生成する限り、複数のエンコーディングが存在するという事実を無視できるため、Webの登場前の比較的限られたファイル交換で、この互換性のないエンコーディングの状況が許容されました。テキストをバイトとして扱います(オペレーティングシステムで使用されるエンコーディングを使用)。正しい最新のビューでは、次の2つのポイントに基づいて、これら2つの文字列の概念を適切に分離しています。
キャラクターはほとんどコンピューターとは無関係です。例えばチョップボードなどにそれらを描くことができます。たとえば、بايثون、中華やandなどです。マシンの「文字」には、スペース、キャリッジリターン、書き込み方向を設定する指示(アラビア語など)、アクセントなどの「描画指示」も含まれます。非常に大きな文字リストがUnicode標準に含まれています。既知の文字のほとんどをカバーしています。
一方、コンピュータは何らかの方法で抽象文字を表す必要があります。そのため、メモリはバイトチャンクで提供されるため、バイトの配列(0〜255の数値を含む)を使用します。文字をバイトに変換するために必要なプロセスは、エンコーディングと呼ばれます。したがって、コンピュータが必要とする文字を表すためにエンコーディングをします。コンピューターに存在するテキストは、(それが表示されるまで)エンコードされます。ターミナルに送信されるか(特定の方法でエンコードされた文字が必要です)、ファイルに保存されます。(たとえば、Pythonインタプリタによって)表示されるか、適切に「理解」されるために、バイトのストリームは文字にデコードされます。いくつかのエンコーディング(UTF-8、UTF-16、…)は、文字のリストに対してUnicodeによって定義されています(したがって、Unicodeは、文字のリストとこれらの文字のエンコーディングの両方を定義します。「Unicodeエンコーディング」という表現が、ユビキタスUTF-8を参照する方法ですが、Unicodeは複数のエンコーディングを提供するため、これは誤った用語です。
要約すると、コンピューターはバイトで文字を内部的に表現する必要があり、次の2つの操作で表現します。
エンコーディング:文字→バイト
デコード:バイト→文字
一部のエンコーディングではすべての文字(ASCIIなど)をエンコードできませんが、(一部の)UnicodeエンコーディングではすべてのUnicode文字をエンコードできます。一部の文字は直接または組み合わせて(たとえば、基本文字とアクセントの)表すことができるため、エンコーディングは必ずしも一意である必要はありません。
改行 の概念は、オペレーティングシステムに依存するさまざまな(制御)文字で表すことができるため、複雑なレイヤーを追加することに注意してください(これがPythonのユニバーサル改行ファイル読み取りモードの理由です)。
ここで、上記で「文字」と呼んでいるのは、Unicodeが「ユーザー認識文字」と呼んでいるものです。単一のユーザー認識文字は、「コードポイント」と呼ばれる、Unicodeリストの異なるインデックスにある文字部分(基本文字、アクセントなど)を組み合わせることにより、Unicodeで表すことができます。これらのコードポイントを組み合わせて、フォームを作成できます。 「書記素クラスター」。したがって、Unicodeは、バイト文字列と文字列の間に位置し、後者に近い、一連のUnicodeコードポイントで構成される文字列の3番目の概念につながります。それらを " Unicode文字列と呼びます Python 2のように」」。
Python は(ユーザーが認識する)文字の文字列を出力できますが、Pythonの非バイト文字列は基本的に、ユーザーが認識する文字ではなく、Unicodeコードポイントのシーケンスです。コードポイント値は、Python \u
および\U
Unicode文字列構文で使用される値です。文字のエンコードと混同しないでください(文字との関係を負う必要はありません。Unicodeコードポイントはさまざまな方法でエンコードできます)。
これには重要な結果があります。Python(Unicode)文字列の長さは、コードポイントの数であり、必ずしもユーザーが認識する文字の数とは限りません。したがって、s = "\u1100\u1161\u11a8"; print(s, "len", len(s))
(Python 3)は、単一のユーザーが認識する(韓国語)각 len 3
にもかかわらずs
文字(3つのコードポイントで表されるため、必要がない場合でも、print("\uac01")
です。ただし、多くの文字は通常Pythonによって単一のUnicodeコードポイントとして格納されるため、多くの実際的な状況では、文字列の長さはユーザーが認識する文字の数になります。
でPythonの2、Unicode文字列は、「Unicode文字列」(...と呼ばれるunicode
タイプ、リテラル形式u"…"
バイト配列は「文字列」(であるが、)str
バイトの配列は、例えば文字列リテラルで構成することができるタイプ"…"
)。でPythonの3、Unicode文字列を単に「文字列」(と呼ばれるstr
タイプ、リテラル形式"…"
バイト配列は「バイト」(であるが、)bytes
タイプ、リテラル形式b"…"
)。結果として、のようなもの"🐍"[0]
は、Python 2('\xf0'
、バイト)とPython 3("🐍"
、最初の唯一の文字)では異なる結果をもたらします。
これらのいくつかの重要なポイントがあれば、エンコーディング関連のほとんどの質問を理解できるはずです!
あなたがする場合、通常、印刷する u"…"
端末に、あなたはゴミを取得するべきではありません:Pythonはあなたの端末のエンコーディングを知っています。実際、端末が予期するエンコーディングを確認できます。
% python
Python 2.7.6 (default, Nov 15 2013, 15:20:37)
[GCC 4.2.1 Compatible Apple LLVM 5.0 (clang-500.2.79)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> print sys.stdout.encoding
UTF-8
入力文字が端末のエンコーディングでエンコードできる場合、Pythonはそれを行い、対応するバイトを文句なしに端末に送信します。端末は、入力バイトをデコードした後に文字を表示するために最善を尽くします(最悪の場合、端末のフォントには一部の文字がなく、代わりにある種の空白が印刷されます)。
入力文字を端末のエンコーディングでエンコードできない場合、端末がこれらの文字を表示するように構成されていないことを意味します。Pythonは文句を言います(PythonではUnicodeEncodeError
、端末に適した方法で文字列をエンコードできないため、aを使用します)。考えられる唯一の解決策は、文字を表示できる端末を使用することです(文字を表現できるエンコードを受け入れるように端末を構成するか、別の端末プログラムを使用します)。これは、さまざまな環境で使用できるプログラムを配布するときに重要です。印刷するメッセージは、ユーザーの端末で表現できる必要があります。したがって、ASCII文字のみを含む文字列を使用するのが最善の場合もあります。
ただし、プログラムの出力をリダイレクトまたはパイプする場合、受信プログラムの入力エンコーディングが何であるかを知ることは通常不可能であり、上記のコードはいくつかのデフォルトのエンコーディングを返します:None(Python 2.7)またはUTF-8( Python 3):
% python2.7 -c "import sys; print sys.stdout.encoding" | cat
None
% python3.4 -c "import sys; print(sys.stdout.encoding)" | cat
UTF-8
ただし、stdin、stdout、およびstderrのエンコーディングは、必要に応じて環境変数を介して設定できPYTHONIOENCODING
ます。
% PYTHONIOENCODING=UTF-8 python2.7 -c "import sys; print sys.stdout.encoding" | cat
UTF-8
端末への印刷で期待どおりの結果が得られない場合は、手動で入力したUTF-8エンコードが正しいことを確認できます。たとえば、私が間違っていなければ、最初の文字(\u001A
)は印刷できません。
でhttp://wiki.python.org/moin/PrintFailsは、Python 2.xのために、次のような解決策を見つけることができます。
import codecs
import locale
import sys
# Wrap sys.stdout into a StreamWriter to allow writing unicode.
sys.stdout = codecs.getwriter(locale.getpreferredencoding())(sys.stdout)
uni = u"\u001A\u0BC3\u1451\U0001D10C"
print uni
Python 3の場合、StackOverflowで以前に尋ねられた質問の1つを確認できます。