文字列とバイト文字列の違いは何ですか?


209

バイト文字列を返すライブラリを使用していますが、これを文字列に変換する必要があります。

違いは何かわかりませんが、もしあれば。

回答:


260

Python 3(Python 2では、この違いは少し明確ではありません)と仮定すると、文字列は文字のシーケンス、つまりUnicodeコードポイントです。これらは抽象的な概念であり、ディスクに直接保存することはできません。バイト文字列は、当然のことながら、バイトのシーケンスです。ディスクに格納できるものです。それらの間のマッピングはエンコーディングです -これらはかなりたくさんあり(そして無限に多くが可能です)-異なるエンコーディングが同じバイトをマップするかもしれないので、変換を行うために特定のケースに当てはまるものを知る必要があります別の文字列に:

>>> b'\xcf\x84o\xcf\x81\xce\xbdo\xcf\x82'.decode('utf-16')
'蓏콯캁澽苏'
>>> b'\xcf\x84o\xcf\x81\xce\xbdo\xcf\x82'.decode('utf-8')
'τoρνoς'

どちらを使用するかがわかったら.decode()、バイト文字列のメソッドを使用して、上記のように適切な文字列を取得できます。完全を期すため.encode()に、文字列のメソッドは逆の方法になります。

>>> 'τoρνoς'.encode('utf-8')
b'\xcf\x84o\xcf\x81\xce\xbdo\xcf\x82'

7
Python 2ユーザーを明確にするために:strタイプはタイプと同じbytesです。この答えは、unicode型(Python 3には存在しない)と型を同等に比較していますstr
craymichael 2016年

3
@KshitijSaraogiもそうではありません。その全文は編集されており、少し残念です。Python 3 strオブジェクトのインメモリ表現は、Python側からアクセスまたは関連しません。データ構造は単なるコードポイントのシーケンスです。下PEP 393、正確な内部エンコーディングはラテン-1、UCS2またはUCS4の一つであり、UTF-8表現は、それが最初に要求された後にキャッシュされてもよいが、それでもCコードは、これらの内部の詳細に依存するから推奨されます。
lvc

1
それらをディスクに直接格納できない場合、それらはどのようにメモリに格納されますか?
z33k 2017年

2
@ore​​tyそれらは正確にその理由で何らかの方法で内部的にエンコードする必要がありますが、これは、浮動小数点数の格納方法を気にする必要がないようなPythonコードからのexpos3ではありません。
lvc

1
@ChrisStryczynskiは上記のコメントを参照してください- 何らかの形でメモリに保存されていることを確認してください。ただし、そのフォームは明示的に抽象化されています。実際、最近では、プログラムの存続期間中に変更され、異なる文字列間で異なる場合があります。また、文字列によっては、複数の文字列(一部のエンコーディングはキャッシュされる)になる場合があります。ただし、心配する必要があるのは、これは、文字列型自体の実装をハッキングしている場合です。
lvc

390

コンピュータが保存できる唯一のものはバイトです。

コンピュータに何かを保存するには、まずそれをエンコードする、つまりバイトに変換する必要があります。例えば:

  • 音楽を保存する場合は、最初MP3WAV、などを使用してエンコードする必要があります。
  • 画像を保存する場合は、最初に、などを使用して画像をエンコードする必要があります。PNGJPEG
  • テキストを保存する場合は、最初ASCIIUTF-8、などを使用してエンコードする必要があります。

MP3WAVPNGJPEGASCIIおよびUTF-8の例でエンコード。エンコーディングは、オーディオ、画像、テキストなどをバイト単位で表す形式です。

Pythonでは、バイト文字列は単なるバイトのシーケンスです。人間が読める形式ではありません。内部的には、すべてをコンピューターに格納する前にバイト文字列に変換する必要があります。

一方、文字列は、単に「文字列」と呼ばれることもあり、文字のシーケンスです。人間が読める形式です。文字列を直接コンピュータに保存することはできません。最初にエンコードする必要があります(バイト文字列に変換)。やなど、文字列をバイト文字列に変換できるエンコーディングは複数ASCIIありUTF-8ます。

'I am a string'.encode('ASCII')

上記のPythonコードは'I am a string'、encodingを使用して文字列をエンコードしASCIIます。上記のコードの結果はバイト文字列になります。印刷すると、Pythonはと表しb'I am a string'ます。ただし、バイト文字列は人間が読み取れるのはなくASCII印刷時にPython バイト文字列デコードするだけであることに注意してください。Pythonでは、バイト文字列はで表されb、その後にバイト文字列のASCII表現が続きます。

エンコードに使用されたエンコードがわかっている場合は、バイト文字列をデコードして文字列に戻すことができます。

b'I am a string'.decode('ASCII')

上記のコードは、元の文字列を返します'I am a string'

エンコードとデコードは逆の操作です。すべてをディスクに書き込む前にエンコードし、人間が読み取る前にデコードする必要があります。


59
Zenadixはここでいくつかの賞賛に値します。この環境で数年働いた後、彼は私と一緒にクリックした最初の説明です。私は「ポジティブUnicodeと文字セット(言い訳について知っておく必要があり、絶対に絶対最小すべてのソフトウェア開発を)ジョエル・スポルスキで!」一方のアームが既に持っている(私の他の腕に刺青があり
neil.millikin

4
絶対に素晴らしい。明快で理解しやすいです。ただし、この行-「印刷すると、Pythonはそれをb'I am a string 'として表す」は、Python2の場合と同様にPython3にも当てはまり、strも同じです。
SRC 2016

5
このテーマを明確にするために、非常に人間が読める形式の説明を提供して、この賞金を授与します。
fedorqui 'SO stop harming'

3
すばらしい答えです。おそらく追加できる唯一のことは、歴史的に、プログラマーとプログラミング言語はバイトシーケンスとASCII文字列が同じものであると明示的または暗黙的に仮定する傾向があったことをより明確に指摘することです。Python 3はこの仮定を明確に破ることに決めました。正しくは私見です。
nekomatic

4
ジョエルさんの投稿へのリンクは、上記@ neil.millikin言及:joelonsoftware.com/2003/10/08/...
Kshitij Saraogi

14

注: Python 2のサポート終了が近づいているため、Python 3についての回答を詳しく説明します。

Python 3では

bytes8ビットの符号なし値strのシーケンスで構成され、人間の言語のテキスト文字を表すUnicodeコードポイントのシーケンスで構成されます。

>>> # bytes
>>> b = b'h\x65llo'
>>> type(b)
<class 'bytes'>
>>> list(b)
[104, 101, 108, 108, 111]
>>> print(b)
b'hello'
>>>
>>> # str
>>> s = 'nai\u0308ve'
>>> type(s)
<class 'str'>
>>> list(s)
['n', 'a', 'i', '̈', 'v', 'e']
>>> print(s)
naïve

にもかかわらずbytesstr同じように動作するように見える、そのインスタンスはすなわち、相互に互換性がない、bytesstrインスタンスは同様の演算子と一緒に使用することはできません>+。さらに、比較bytesstrインスタンスの等価性、つまりの使用は==Falseまったく同じ文字が含まれている場合でも常に評価されることに注意してください。

>>> # concatenation
>>> b'hi' + b'bye' # this is possible
b'hibye'
>>> 'hi' + 'bye' # this is also possible
'hibye'
>>> b'hi' + 'bye' # this will fail
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't concat str to bytes
>>> 'hi' + b'bye' # this will also fail
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can only concatenate str (not "bytes") to str
>>>
>>> # comparison
>>> b'red' > b'blue' # this is possible
True
>>> 'red'> 'blue' # this is also possible
True
>>> b'red' > 'blue' # you can't compare bytes with str
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '>' not supported between instances of 'bytes' and 'str'
>>> 'red' > b'blue' # you can't compare str with bytes
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: '>' not supported between instances of 'str' and 'bytes'
>>> b'blue' == 'red' # equality between str and bytes always evaluates to False
False
>>> b'blue' == 'blue' # equality between str and bytes always evaluates to False
False

扱う別の問題bytesstr使用して返されたファイルを扱うときに存在するopenビルトイン機能を。一方では、バイナリデータをファイルとの間で読み書きする場合は、常に「rb」や「wb」などのバイナリモードを使用してファイルを開きます。一方、ファイルとの間でUnicodeデータを読み書きする場合は、コンピューターのデフォルトのエンコードに注意してくださいencoding。必要に応じて、パラメーターを渡して予期しない事態を回避してください。

Python 2では

str8ビット値unicodeのシーケンスで構成され、Unicode文字のシーケンスで構成されます。心に留めておくべきことの一つは、ということですstrし、unicodeあればオペレーターと一緒に使用することができるstr唯一の7ビットのASCI文字で構成されています。

ヘルパー関数を使用strしてunicode、Python 2とPython 2、Python 3 bytesstrPython 3の間で変換すると便利な場合があります。


4

以下からのUnicodeとは何ですか

基本的に、コンピューターは数値を処理するだけです。彼らはそれぞれに番号を割り当てることにより、文字やその他の文字を格納します。

……

Unicodeは、プラットフォーム、プログラム、言語に関係なく、すべての文字に一意の番号を提供します。

したがって、コンピュータが文字列を表す場合、コンピュータは文字列のコンピュータに格納されている文字を一意のUnicode番号を介して検索し、これらの数字はメモリに格納されます。ただし、これらの数値は単なる10進数であるため、文字列をディスクに直接書き込んだり、一意のUnicode番号を介してネットワーク上で送信したりすることはできません。文字列は、などのバイト文字列にエンコードする必要がありますUTF-8UTF-8可能なすべての文字をエンコードできる文字エンコードであり、文字をバイトとして格納します(このようになります)。エンコードされた文字列UTF-8は、ほぼどこでもサポートされているため、どこでも使用できます。でエンコードされたテキストファイルを開くとUTF-8他のシステムからの場合、コンピューターはそれをデコードし、固有のUnicode番号を介してその中の文字を表示します。ブラウザがUTF-8ネットワークからエンコードされた文字列データを受信すると、データを文字列にデコードし(ブラウザがUTF-8エンコードされていると想定)、文字列を表示します。

python3では、文字列とバイト文字列を相互に変換できます。

>>> print('中文'.encode('utf-8'))
b'\xe4\xb8\xad\xe6\x96\x87'
>>> print(b'\xe4\xb8\xad\xe6\x96\x87'.decode('utf-8'))
中文 

つまり、文字列はコンピュータで読み取るために人間に表示するためのものであり、バイト文字列はディスクへの格納とデータ転送のためのものです。


1

Unicodeは、文字とさまざまな種類のフォーマット(小文字/大文字、改行、キャリッジリターンなど)のバイナリ表現、およびその他の "もの"(絵文字など)について合意された形式です。コンピューターは、ASCII表現(別の一連のビット)または他の表現(一連のビット)を保存するのと同じくらい、ユニコード表現(一連のビット)をメモリまたはファイルに保存することができます。 )。

以下のための通信が行われるように、通信の当事者が使用されますどのような表現に同意しなければなりません。

ユニコードは、人とコンピュータ間の通信で使用されるすべての可能な文字(およびその他の「もの」)を表現しようとするため、多くの文字(またはもの)の表現には、他の表現システムよりも多くのビット数が必要です。より限定された文字/もののセットを表すようにしてください。「単純化」し、おそらく歴史的な使用法に対応するために、Unicode表現は、ほとんどの場合、文字をファイルに格納する目的で、他の何らかの表現システム(ASCIIなど)に変換されます。

これは、Unicodeがいる場合ではないことができないファイル内の文字を格納し、またはを介してそれらを送信するために使用される任意のそれは単にことを、通信チャネルはありません。

「文字列」という用語は正確に定義されていません。「文字列」は、その一般的な用法では、文字/もののセットを指します。コンピュータでは、これらの文字は、多くの異なるビットごとの表現のいずれかに格納されます。「バイト文字列」は、8ビットを使用する表現を使用して格納された文字のセットです(8ビットはバイトと呼ばれます)。最近では、コンピューターはユニコードシステム(可変数のバイトで表される文字)を使用してメモリに文字を格納し、バイト文字列(1バイトで表される文字)は文字をファイルに格納するため、表される文字の前に変換を使用する必要がありますメモリ内のファイル内のストレージに移動されます。


0

単純な1文字の文字列'š'を用意し、それをバイトのシーケンスにエンコードしてみましょう。

>>> 'š'.encode('utf-8')
b'\xc5\xa1'

この例では、バイトシーケンスをバイナリ形式で表示します。

>>> bin(int(b'\xc5\xa1'.hex(), 16))
'0b1100010110100001'

現在、情報がどのようにエンコードされているかを知らずに情報をデコードすることは一般に不可能です。utf-8テキストエンコーディングが使用されたことがわかっている場合にのみ、utf-8をデコードするためアルゴリズムに従って、元の文字列を取得できます。

11000101 10100001
   ^^^^^   ^^^^^^
   00101   100001

2進数を101100001文字列として表示し直すことができます。

>>> chr(int('101100001', 2))
'š'

0

Python言語にはstrbytes標準の「組み込み型」が含まれています。つまり、どちらもクラスです。Pythonがこのように実装された理由を合理化しようとする価値はないと思います。

有することを言った、strそしてbytes互いに非常に類似しています。どちらもほとんど同じ方法を共有しています。次のメソッドはstrクラスに固有です。

casefold
encode
format
format_map
isdecimal
isidentifier
isnumeric
isprintable

次のメソッドはbytesクラスに固有です。

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