Python strとUnicodeタイプ


101

Python 2.7で作業しているときに、のunicode代わりにタイプを使用することにはどのような真の利点があるのだろうと思いstrます。どちらもUnicode文字列を保持できるようです。unicodeエスケープ文字を使用して文字列にUnicodeコードを設定できること以外に、特別な理由はあります\か?

以下を使用してモジュールを実行する:

# -*- coding: utf-8 -*-

a = 'á'
ua = u'á'
print a, ua

結果:á、á

編集:

Pythonシェルを使用したテスト:

>>> a = 'á'
>>> a
'\xc3\xa1'
>>> ua = u'á'
>>> ua
u'\xe1'
>>> ua.encode('utf8')
'\xc3\xa1'
>>> ua.encode('latin1')
'\xe1'
>>> ua
u'\xe1'

したがって、unicode文字列はのlatin1代わりにutf-8を使用してエンコードされているようで、生の文字列はutf-8?私は今さらに混乱しています!:S


エンコーディングはありませんunicode。Unicode文字の抽象化にすぎません。いくつかのエンコーディングunicodeで変換できますstr(例:)utf-8
Bin

回答:


178

unicodeテキストを処理するためのものです。テキストは一連のコードポイントあり、1バイトより大きい場合があります。テキストをすることができる符号化された生のバイトとしてテキストを表現するために、特定の符号化(例えばutf-8latin-1...)。

unicode エンコードされいないことに注意してください!Pythonで使用される内部表現は実装の詳細であり、必要なコードポイントを表現できる限り、気にする必要はありません。

反対strにPython 2では、単純なバイトシーケンスです。テキストを表すものではありません!

unicodeいくつかのテキストの一般的な表現と考えることができます。これは、を介して表される一連のバイナリデータにさまざまな方法でエンコードできますstr

注:Python 3では、unicodeに名前が変更され、単純なバイトシーケンス用のstr新しいbytesタイプがあります。

あなたが見ることができるいくつかの違い:

>>> len(u'à')  # a single code point
1
>>> len('à')   # by default utf-8 -> takes two bytes
2
>>> len(u'à'.encode('utf-8'))
2
>>> len(u'à'.encode('latin1'))  # in latin1 it takes one byte
1
>>> print u'à'.encode('utf-8')  # terminal encoding is utf-8
à
>>> print u'à'.encode('latin1') # it cannot understand the latin1 byte

を使用strすると、特定のエンコーディング表現の1バイトを下位レベルで制御unicodeできますが、使用するとコードポイントレベルでしか制御できないことに注意してください。たとえば、次のことができます。

>>> 'àèìòù'
'\xc3\xa0\xc3\xa8\xc3\xac\xc3\xb2\xc3\xb9'
>>> print 'àèìòù'.replace('\xa8', '')
à�ìòù

以前は有効なUTF-8でしたが、もうありません。Unicode文字列を使用すると、結果の文字列が有効なUnicodeテキストではない方法で操作することはできません。コードポイントを削除したり、コードポイントを別のコードポイントに置き換えたりできますが、内部表現を変更することはできません。


4
あなたの答えに感謝します、それはとても役に立ちました!私にとって最も明確な部分は、「Unicodeはエンコードされていません!Pythonで使用される内部表現は実装の詳細であり、気にする必要はありません[...]」です。したがって、unicodeオブジェクトをシリアル化する場合、どのオブジェクトencode()が内部でunicode値を表すために使用されているのかわからないため、まずオブジェクトを適切なエンコード形式に明示的に指定する必要があると思います。
Caumons 2013

10
はい。一部のテキスト(ファイルなど)を保存する場合は、それをバイトで表す必要があります。つまり、エンコードする必要があります。コンテンツを取得するとき、バイトをオブジェクトにデコードできるようにするために、使用されたエンコーディングを知っている必要がありunicodeます。
Bakuriu 2013

申し訳ありませんが、unicodeエンコードされていないステートメントは明らかに間違っています。UTF-16 / UCS-2およびUTF-32 / UCS-4もエンコーディングです。将来的にはさらに多くのものが作成される可能性があります。重要なのは、実装の詳細を気にする必要がない(実際、気にする必要がない!)からといって、それunicodeがエンコードされていないという意味ではありません。もちろんです。それができるかどうか.decode()はまったく別の話です。
0xC0000022L 2016

1
@ 0xC0000022L多分それが不明確なので文は。それは言うべきです:unicodeオブジェクトの内部表現は、非標準のものを含め、それが望むものにすることができます。特にpython3 + unicode では、含まれているデータに応じて変化する非標準の内部表現を使用ます。そのため、標準のエンコーディングではありません。テキスト標準としてのUnicodeは、テキストの抽象的な表現であるコードポイントのみを定義します。標準のutf-Xなどを含め、メモリにユニコードをエンコードする方法はたくさんあります。Pythonは効率のために独自の方法を使用します。
バクリウ2016

1
@ 0xC0000022Lまた、UTF-16がエンコーディングであるという事実は、UTF-16もUTF-32も使用しないため、CPythonのオブジェクトとは何の関係もunicodeありません。アドホック表現を使用しており、データを実際のバイトにエンコードする場合は、を使用する必要がありますencode。また、言語unicodeは実装方法を義務付けていないため、Pythonのバージョンや実装が異なると、内部表現も異なる可能性があります
バクリウ2016

38

Unicodeとエンコーディングは完全に異なり、無関係です。

Unicode

各文字に数値IDを割り当てます。

  • 0x41→A
  • 0xE1→á
  • 0x414→Д

したがって、Unicodeは0x41をAに、0xE1をáに、0x414をДに割り当てます。

小さな矢印→私が使用したものにもUni​​code番号があり、0x2192です。絵文字にもUni​​code番号があり、😂は0x1F602です。

この表のすべての文字のUnicode番号を検索できます。特に、あなたは上記の最初の3つの文字を見つけることができ、ここに、矢印ここでは、絵文字ここに

Unicodeによってすべての文字に割り当てられるこれらの番号は、コードポイントと呼ばれます

これらすべての目的は、各文字を明確に参照する手段を提供することです。たとえば、私がaboutについて話している場合、「ご存知のように、涙を浮かべて笑うこの絵文字」ではなく、Unicodeコードポイント0x1F602と言えます。より簡単ですよね?

Unicodeコードポイントは通常、先頭U+にを付けてフォーマットされ、次に16進数の数値が少なくとも4桁に埋め込まれます。したがって、上記の例はU + 0041、U + 00E1、U + 0414、U + 2192、U + 1F602になります。

Unicodeコードポイントの範囲はU + 0000からU + 10FFFFです。それは1,114,112個の数字です。これらの数のうち2048はサロゲートに使用されるため、1,112,064が残ります。つまり、Unicodeは1,112,064の異なる文字に一意のID(コードポイント)を割り当てることができます。これらのコードポイントのすべてがまだ文字に割り当てられているわけではなく、Unicodeは継続的に拡張されます(たとえば、新しい絵文字が導入されたとき)。

覚えておくべき重要なことは、すべてのUnicodeが、コードポイントと呼ばれる数値IDを各文字に割り当てて、簡単で明確な参照ができることです。

エンコーディング

文字をビットパターンにマップします。

これらのビットパターンは、コンピュータメモリまたはディスク上の文字を表すために使用されます。

文字の異なるサブセットをカバーする多くの異なるエンコーディングがあります。英語圏では、最も一般的なエンコーディングは次のとおりです。

ASCII

128文字(コードポイントU + 0000〜U + 007F)を長さ7のビットパターンにマップします。

例:

  • a→1100001(0x61)

このですべてのマッピングを確認できます

ISO 8859-1(別名Latin-1)

191文字(コードポイントU + 0020からU + 007EおよびU + 00A0からU + 00FF)を長さ8のビットパターンにマップします。

例:

  • a→01100001(0x61)
  • á→11100001(0xE1)

このですべてのマッピングを確認できます

UTF-8

1,112,064文字(既存のすべてのUnicodeコードポイント)を長さ8、16、24、または32ビット(つまり、1、2、3、または4バイト)のビットパターンにマップします。

例:

  • a→01100001(0x61)
  • á→11000011 10100001(0xC3 0xA1)
  • ≠→11100010 10001001 10100000(0xE2 0x89 0xA0)
  • 😂→11110000 10011111 10011000 10000010(0xF0 0x9F 0x98 0x82)

UTF-8が文字をビット文字列にエンコードする方法は、ここで非常によく説明されています

Unicodeとエンコーディング

上記の例を見ると、Unicodeがどのように役立つかが明らかになります。

たとえば、私がLatin-1であり、自分のáのエンコーディングを説明したい場合は、言う必要はありません。

「aをaiguでエンコードします(または、立ち上がりバーと呼んでいます)を11100001としてエンコードします

しかし、私はただ言うことができます:

「U + 00E1を11100001としてエンコードします

そして、私がUTF-8なら、私は言うことができます:

「次に、U + 00E1を11000011 10100001としてエンコードします。

そして、私たちがどのキャラクターを意味するかは、誰にとっても明白です。

今度は頻繁に発生する混乱に

場合によっては、エンコードのビットパターンを2進数として解釈すると、この文字のUnicodeコードポイントと同じになることがあります。

例えば:

  • ASCIIはaを1100001としてエンコードます。これは16進数0x61として解釈でき、aの UnicodeコードポイントはU + 0061です。
  • Latin-1はáを11100001としてエンコードします。これは16進数0xE1として解釈でき、áの UnicodeコードポイントはU + 00E1です。

もちろん、これは便宜上、このように配置されています。しかし、あなたはそれを純粋な偶然と見なすべきです。メモリ内の文字を表すために使用されるビットパターンは、この文字のUnicodeコードポイントに関連付けられていません。

11100001のようなビット文字列を2進数として解釈する必要があると言う人はいません。Latin-1が文字áをエンコードするために使用するビットのシーケンスとして見てください。

あなたの質問に戻る

Pythonインタープリターで使用されるエンコードはUTF-8です。

これがあなたの例で起こっていることです:

例1

以下は、文字áをUTF-8でエンコードします。これにより、ビット文字列11000011 10100001が生成され、変数に保存されますa

>>> a = 'á'

の値を見るとa、その内容11000011 10100001は16進数0xC3 0xA1としてフォーマットされ、次のように出力され'\xc3\xa1'ます。

>>> a
'\xc3\xa1'

例2

次のコードは、UのU + 00E1であるáのUnicodeコードポイントを変数uaに保存します(Pythonがメモリ内のコードポイントU + 00E1を表すために内部で使用するデータ形式は不明であり、重要ではありません)。

>>> ua = u'á'

の値を見るとua、PythonにはコードポイントU + 00E1が含まれていることが表示されます。

>>> ua
u'\xe1'

例3

次に、UnicodeコードポイントU + 00E1(文字áを表す)をUTF-8でエンコードします。これにより、ビットパターンは11000011 10100001になります。ここでも、出力の場合、このビットパターンは16進数0xC3 0xA1として表されます。

>>> ua.encode('utf-8')
'\xc3\xa1'

実施例4

次の符号化Unicodeコードポイントラテン1、出力のビットパターン11100001.の結果は、このビットパターンが進数0xE1の、のように表されるとU + 00E1(表す文字A)に一致することにより、初期と同じですコードポイントU + 00E1:

>>> ua.encode('latin1')
'\xe1'

UnicodeオブジェクトuaとLatin-1エンコーディングの間には何の関係もありません。áのコードポイントがU + 00E1であり、áのLatin-1エンコードが0xE1である(エンコードのビットパターンを2進数として解釈する場合)ことは、まったくの偶然です。


31

端末がたまたまUTF-8に設定されています。

印刷がa機能するという事実は偶然です。端末に生のUTF-8バイトを書き込んでいます。aは、2バイトの16進値C3とA1を含む長さ2のua値ですが、コードポイントU + 00E1を含む長さ1のユニコード値です。

この長さの違いは、Unicode値を使用する主な理由の1つです。バイト文字列のテキスト文字数を簡単に測定することはできません。len()バイト列のは、エンコードされた文字数ではなく、使用されたバイト数を示します。

ユニコード値を異なる出力エンコーディングにエンコードすると、違いがわかります。

>>> a = 'á'
>>> ua = u'á'
>>> ua.encode('utf8')
'\xc3\xa1'
>>> ua.encode('latin1')
'\xe1'
>>> a
'\xc3\xa1'

Unicode標準の最初の256コードポイントはLatin 1標準と一致するため、U + 00E1コードポイントは16進値E1のバイトとしてLatin 1にエンコードされます。

さらに、Pythonはユニコードとバイト文字列の表現に同様にエスケープコードを使用し、印刷可能なASCIIではない低いコードポイントも\x..エスケープ値を使用して表されます。これは、なぜ128と255ルックスの間のコード・ポイントを持つUnicode文字列だけでラテン1つのエンコードのような。U + 00FFを超えるコードポイントを持つユニコード文字列がある場合は、\u....代わりに4桁の16進数値を持つ別のエスケープシーケンスが使用されます。

Unicodeとエンコーディングの違いはまだ十分に理解していないようです。続行する前に、次の記事をお読みください。


さらにテストを行って質問を編集しました。私は、Unicodeとしばらくの間、異なるエンコーディングのために読んでいると私は理論を理解すると思うが、実際にPythonのコードをテストするとき、私は何が起こってキャッチしない
Caumons

1
latin-1エンコーディングは、Unicode標準の最初の256コードポイントと一致します。U + 00E1は、にエンコードする理由はここにある\xe1ラテン1に
マルタインピータース

2
これがユニコードにとって最も重要な側面の1つです。エンコーディングではありません。テキストです。Unicodeは標準であり、コードポイントとは何か、数値、空白やその他のカテゴリなどの情報は、左から右または右から左などに表示する必要があります。など
Martijn Pieters

1
Unicodeは「インターフェース」のようなもので、エンコーディングは実際の「実装」のようなものです。
Caumons 2013

2
@Varun:内部的にUCS-2を使用し、長さが2であるとしてU + FFFFを超えるものを誤って表すPython 2ナロービルドを使用している必要があります。Python 3とUCS-2(ワイド)ビルドでは、長さが本当に1であることが
わかり

2

aをユニコードとして定義すると、文字aとáは等しくなります。それ以外の場合、áは2文字としてカウントされます。len(a)とlen(au)を試してください。それに加えて、他の環境で作業するときにエンコードが必要になる場合があります。たとえば、md5を使用すると、aとuaの値が異なります

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.