[解決!Python]文字列とバイト列を相互に変換するには解決!Python

文字列とバイト列を相互に変換するには、文字列のencodeメソッドとバイト列のdecodeメソッドを使うか、str関数とbytes関数を使うのが簡単だ。それらの方法を紹介する。

» 2024年06月04日 05時00分 公開
[かわさきしんじDeep Insider編集部]
「解決!Python」のインデックス

連載目次

# 文字列をバイト列に変換する
s0 = 'Hello, world!'
b0 = s0.encode()  # デフォルトのエンコーディングはUTF-8
print(b0)  # b'Hello, world!'

# バイト列を文字列に変換する
s1 = b0.decode()  # デフォルトのエンコーディングはUTF-8
print(s1)  # Hello, world!

# エンコーディングを指定してバイト列に変換する
s0 = 'ディープ'
b0 = s0.encode(encoding='utf-8'# UTF-8でエンコード
print(b0)  # b'\xe3\x83\x87\xe3\x82\xa3\xe3\x83\xbc\xe3\x83\x97'

b1 = s0.encode(encoding='shift-jis'# Shift-JISでエンコード
print(b1)  # b'\x83f\x83B\x81[\x83v'

# エンコーディングを指定してバイト列を文字列に変換する
s1 = b0.decode(encoding='utf-8'# UTF-8でデコード
print(s1)  # ディープ

s2 = b1.decode(encoding='shift-jis'# Shift-JISでデコード
print(s2)  # ディープ

# 指定したエンコードで変換できないと例外が発生する
s1 = b0.decode(encoding='shift-jis'# UnicodeDecodeError
s2 = b1.decode(encoding='utf8'# UnicodeDecodeError

b3 = '♡'.encode(encoding='sjis'# UnicodeEncodeError

# 変換できないときの処理をerrorsパラメーターで指定する
b3 = '♡'.encode(encoding='sjis', errors='ignore'# エラーを無視
print(b3)  # b''
b3 = '♡'.encode(encoding='sjis', errors='replace'# ?に置き換える
print(b3)  # b'?'
b3 = '♡'.encode(encoding='sjis', errors='backslashreplace'# \uXXXXに置き換え
print(b3)  # b'\\u2661'

# bytes関数/str関数を使って文字列とバイト列を相互に変換する
s0 = 'Hello, world!'
b0 = s0.encode()

# bytes関数で文字列をバイト列に変換する(encodingパラメーターの指定が必須)
b1 = bytes(s0, encoding='utf8')
print(b1)  # b'Hello, world!'

# str関数にバイト列を渡して文字列に変換する(encodingパラメーターの指定が必須)
s1 = str(b0, encoding='utf8')
print(s1)  # Hello, world!

# バイト列を16進数の文字列に変換する
s2 = b0.hex()
print(s2)  # 48656c6c6f2c20776f726c6421

s2 = b0.hex(sep=' ')
print(s2)  # 48 65 6c 6c 6f 2c 20 77 6f 72 6c 64 21


文字列とバイト列の変換

 文字列をバイト列に変換するには文字列のencodeメソッドを使用し、逆にバイト列を文字列に変換するにはバイト列のdecodeメソッドを使用するのが一般的だ。str関数やbytes関数でencodingパラメーターを指定することでも変換できるが、これについては後述する。

 以下は文字列をバイト列に変換するシンプルな例を示す。

s0 = 'Hello, world!'
b0 = s0.encode()  # デフォルトのエンコーディングはUTF-8
print(b0)  # b'Hello, world!'


 Python 3では文字列のデフォルトのエンコーディングはUTF-8であり、encodeメソッドでもUTF-8エンコードされたバイト列に文字列を変換する。上の例ではASCIIの範囲に収まる文字列をバイト列にエンコードしたので、「b'Hello, world!'」のように可読性のあるバイト列が返されている。

 バイト列を文字列に変換するには既に述べた通りdecodeメソッドを用いる。上で変換したバイト列をdecodeメソッドで文字列に変換してみよう。

s1 = b0.decode()  # デフォルトのエンコーディングはUTF-8
print(s1)  # Hello, world!


 decodeメソッドでもデフォルトのエンコーディングはUTF-8となっているので、バイト列はUTF-8でエンコードされたものとして文字列に変換される。その結果はもちろん「Hello, world!」である。

エンコーディングの指定

 encodeメソッド/decodeメソッドのencodeパラメーターにはさまざまな値を指定できる。encodeメソッドのencodingパラメーターを指定すると文字列は指定されたエンコーディングでバイト列に変換されるし、decodeメソッドのencodingパラメーターを指定するとバイト列は指定されたエンコーディングを用いて文字列に変換される。

 例えば、以下は(デフォルトのエンコーディングである)UTF-8を明示的に指定している。

s0 = 'ディープ'
b0 = s0.encode(encoding='utf-8'# UTF-8でエンコード
print(b0)  # b'\xe3\x83\x87\xe3\x82\xa3\xe3\x83\xbc\xe3\x83\x97'


 一方、以下の例ではシフトJISで文字列をバイト列にエンコードするものだ。

b1 = s0.encode(encoding='shift-jis'# Shift-JISでエンコード
print(b1)  # b'\x83f\x83B\x81[\x83v'


 エンコーディングの違いで得られるバイト列が異なっている点に注意しよう。

 decodeメソッドでバイト列を文字列に変換するときも同様だ。以下の最初の例ではUTF-8でエンコードされたバイト列を文字列に、次の例ではシフトJISでエンコードされたバイト列を文字列に変換している。

s1 = b0.decode(encoding='utf-8'# UTF-8でデコード
print(s1)  # ディープ

s2 = b1.decode(encoding='shift-jis'# Shift-JISでデコード
print(s2)  # ディープ


 encodingパラメーターに指定可能な値についてはPythonのドキュメント「標準エンコーディング」や「Python 特有のエンコーディング」などを参照されたい。

 なお、指定したエンコーディングでエンコード/デコードできないときには例外が発生する。以下はその例だ。

s1 = b0.decode(encoding='shift-jis'# UnicodeDecodeError
s2 = b1.decode(encoding='utf8'# UnicodeDecodeError

b3 = '♡'.encode(encoding='sjis'# UnicodeEncodeError


 最初の行は先ほど「ディープ」という文字列をUTF-8でエンコードした結果のバイト列をシフトJISエンコーディングとしてデコードしようとしている。次の行は「ディープ」をシフトJISでエンコードした結果のバイト列をUTF-8エンコーディングとしてデコードしようとしている。そのため、どちらもUnicodeDecodeError例外が発生する。

 最後の行は「♡」をシフトJISでエンコードしようとしているが、「encoding='sjis'」の指定で利用されるコーデック(シフトJISエンコーディングでエンコード/デコードを行うオブジェクト)は、この文字をエンコードできないためUnicodeEncodeError例外が発生する(encodingに'shift_jis_2004'または'shift_jisx0213'を指定するとJIX X 0213:2004で割り当てられている0x83bbへとエンコードできる)。

 例外を発生させるのではなく、変換できない文字を無視したり、「?」に置き換えたり、別の何かに置き換えたりしたいときにはerrorsパラメーターを指定する。指定可能な値を幾つか以下に示す。詳細についてはPythonのドキュメント「エラーハンドラ」を参照のこと。

  • 'strict':例外を発生させる(デフォルトの動作)
  • 'ignore':変換できないデータを無視して処理を続ける
  • 'replace':エンコード時には変換できないデータをASCIIの?に、デコード時には変換できないデータを'\\ufffd'に変換する
  • 'backslashreplace':変換できないデータをバックスラッシュでエスケープする

 以下に例を示す。

b3 = '♡'.encode(encoding='sjis', errors='ignore'# エラーを無視
print(b3)  # b''
b3 = '♡'.encode(encoding='sjis', errors='replace'# ?に置き換える
print(b3)  # b'?'
b3 = '♡'.encode(encoding='sjis', errors='backslashreplace'# \uXXXXに置き換え
print(b3)  # b'\\u2661'


bytes関数/str関数を使って文字列とバイト列を相互に変換する

 str関数にバイト列を渡すことで文字列に、bytes関数に文字列を渡すことでバイト列に変換することも可能だ。ただし、このときにはencodingパラメーターの指定が必須となる(str関数にバイト列のみを渡すことは可能だが、その場合にはその表示用の文字列表現が得られるだけでバイト列が文字列へデコードされることはない。例えば、「str(b'foo')」は「"b'foo'"」を返す)。

 以下に例を示す。

s0 = 'Hello, world!'
b0 = s0.encode()

# bytes関数で文字列をバイト列に変換する(encodingパラメーターの指定が必須)
b1 = bytes(s0, encoding='utf8')
print(b1)  # b'Hello, world!'

# str関数にバイト列を渡して文字列に変換する(encodingパラメーターの指定が必須)
s1 = str(b0, encoding='utf8')
print(s1)  # Hello, world!


 encode/decodeメソッドと同様、errorsパラメーターも指定できる(例は省略)。

バイト列を16進数の文字列に変換する

 バイト列の値を16進数表現した文字列に変換することも可能だ。これにはバイト列のhexメソッドを使用する。

s2 = b0.hex()
print(s2)  # 48656c6c6f2c20776f726c6421


 この例ではb'Hello, World!'というバイト列の各要素の値を16進数表現した文字列が得られている。ただし、可読性が低い。読みやすくするには、sepパラメーターに区切り文字を指定し、さらにオプションでbytes_per_sepパラメーターに「何バイトごとに区切り文字を表示するか」を指定する。以下はsepパラメーターの使用例だ。

s2 = b0.hex(sep=' ')
print(s2)  # 48 65 6c 6c 6f 2c 20 77 6f 72 6c 64 21


「解決!Python」のインデックス

解決!Python

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。