Pythonで文字列(str)をバイト型(bytes)に変換する方法について解説します。
Contents
Pythonにおける文字列(str)の扱い
Pythonは文字列情報をUnicodeデータとして保存しています。Pythonを利用する環境により、Pythonのファイル(.py)がUTF-8ではなく、それ以外の文字コードで記述されている場合もあります(WindowsではShift-JISなど)。
このような場合でも、Pythonは正常に文字列を扱えるように文字列のエンコーディング情報を管理しており、文字列をエンコード変換して利用しています。この処理はPythonが内部的に実施するためプログラマが意識することは基本的には必要ありません。
しかし、別アプリと文字列をやり取りするような場合などを考慮した場合に、文字コードを意識して文字列を扱う必要が出てきます。
このような場合によく使用するメソッドがencodeメソッドです。その逆のメソッドとして、decodeメソッドがあります。以降では、encodeおよびdecodeメソッドの使い方を紹介していきます。
文字列をバイトに変換する encode (str→bytes)
Pythonで指定した文字コードに文字列を変換する場合には、encodeメソッドを使用します。
以下の「おはようございます。」という文字列をShift-JISでエンコーディングする簡単な例で見てみます。
data = 'おはようございます。' # encodeで指定文字コードにエンコードする encode_data = data.encode('shift_jis') print(encode_data) print(type(encode_data))
【実行結果】 b'\x82\xa8\x82\xcd\x82\xe6\x82\xa4\x82\xb2\x82\xb4\x82\xa2\x82\xdc\x82\xb7\x81B' <class 'bytes'>
encodeメソッドを使うと、指定した文字コードにエンコードしたデータをbytes型として返却します。上記の実行結果にあるように「b'.......'」と出力されているのは、bytes型であることを示しています。
文字コードとしては他にも、'euc_jp'や'iso2022_jp'などもあります。また、例えば'shift_jis'であれば、別名として'sjis'や's_jis'などで指定しても構いません。利用できる標準エンコーディングと別名はこちらで確認ができます。
バイト列は0~255の値の羅列なので、外部のシステムなどとのやり取りも簡単です。受け取った側は何の文字コードでエンコーディングしているかさえ知っていれば、適切に自分の環境で元の文字列に戻すことができます。
encodeされたbytes型のデータをもとに戻すには、次に説明するdecodeメソッドを使用します。
バイトを文字列に変換する decode (bytes→str)
encodeメソッドでbytes型にした値を元の文字列(str)に戻す際には、decodeメソッドを使用します。
decodeメソッドを使用する例を以下で見てみます。
data = 'おはようございます。' # encodeで指定文字コードにエンコードする encode_data = data.encode('shift_jis') print(encode_data) print('================================') # decodeで文字列に戻す decode_data = encode_data.decode('shift_jis') print(decode_data) print(type(decode_data))
【実行結果】 b'\x82\xa8\x82\xcd\x82\xe6\x82\xa4\x82\xb2\x82\xb4\x82\xa2\x82\xdc\x82\xb7\x81B' ================================ おはようございます。 <class 'str'>
上記例は「おはようございます。」という文字列をshift_jisでエンコードして、その後decodeメソッドで元の文字列に戻しています。
文字列に戻す際に、間違った文字コード(例えば'utf_8')を指定すると以下のようにエラーになることがあるため注意しましょう。
data = 'おはようございます。' # encodeで指定文字コードにエンコードする encode_data = data.encode('shift_jis') print(encode_data) print('================================') # decodeで文字列に戻す decode_data = encode_data.decode('utf_8') print(decode_data) print(type(decode_data))
【実行結果例】 UnicodeDecodeError: 'utf-8' codec can't decode byte 0x82 in position 0: invalid start byte
encode/decode失敗時の挙動の指定
正しくエンコードやデコードができない場合の指定は、encode/decodeともにerrorsという引数で挙動を指定することができます。引数として指定できる値と内容は以下の通りです。
なお、デフォルトではerrorsはstrictになっているため、上記の例で見てきたようにエラーが出力されます。
errorsの設定値 | 内容 |
---|---|
strict | 例外を発生して処理を中止する |
ignore | 変換できない文字は除去して、そのまま処理を実行する |
replace | 変換できない文字を「?」等に置換する |
上記のdecodeで失敗した例で「errors=replace」を指定した場合を見てみましょう。
data = 'おはようございます。' # encodeで指定文字コードにエンコードする encode_data = data.encode('shift_jis') print(encode_data) print('================================') # decodeで文字列に戻す decode_data = encode_data.decode('utf_8', errors='replace') print(decode_data) print(type(decode_data))
【実行結果】 b'\x82\xa8\x82\xcd\x82\xe6\x82\xa4\x82\xb2\x82\xb4\x82\xa2\x82\xdc\x82\xb7\x81B' ================================ ���͂悤�������܂��B <class 'str'>
この例だと一部認識できない部分は「�」となっています。replaceなどは、一般的には一部の認識できない文字をスキップする場合などに使用します。
また、「errors=ignore」を指定した場合では、変換のできない文字は以下のように除去されます。
data = 'おはようございます。' # encodeで指定文字コードにエンコードする encode_data = data.encode('shift_jis') print(encode_data) print('================================') # decodeで文字列に戻す decode_data = encode_data.decode('utf_8', errors='ignore') print(decode_data) print(type(decode_data))
【実行結果】 b'\x82\xa8\x82\xcd\x82\xe6\x82\xa4\x82\xb2\x82\xb4\x82\xa2\x82\xdc\x82\xb7\x81B' ================================ ͂悤܂B <class 'str'>
上記に例を見てきましたが、いずれにしても適切な文字に変換ができていないことは事実です。errors引数で処理の挙動を変更できるわけですが、文字コードについてはよく確認してプログラムをするように意識するようにしましょう。
Python2とPython3での文字列/バイト列の扱いの違い
文字列とバイト列の扱いは、Python2からPython3になった際に大きく変更されています。最近はPython3に置き換わってきている印象ですが、もしPython2を使用している場合は注意が必要です。
Python2ではstr型は内部的にはバイト列として扱われていたので、Python3でいうところのbytesに相当しています。Python3でいうところのstrに相当するのは、Python2ではunicode型のため、接頭辞として「u」を付けて「u'おはようございます。'」のような形で表記します。
もし過去から利用しているPython2をPython3に移植するといったことをする場合には、上記のような違いは意識するようにしましょう。
文字列とバイト型の相互変換については、外部システムのやり取りや暗号化/復号化の際などにも使用したりしますのでしっかりと覚えておくとよいでしょう。
上記で紹介しているソースコードについてはgithubにて公開しています。参考にしていただければと思います。