Masayan tech blog.

  1. ブログ記事一覧>
  2. Pythonのエンコード、デコード周りで最低限押さえておきたい事項

Pythonのエンコード、デコード周りで最低限押さえておきたい事項

公開日

環境

  • Python 3.9

文字列をバイトにバイトを文字列に変換

コンストラクターを使用

文字列→バイト

bytes(string, encoding)を使用して変換可能。先頭に付いているbは、「バイト列」を意味する記号。バイト文字に変換したら、日本語はエンコードされる

s = 'Foo'
 
b = bytes(s, 'utf-8')
print(b) # b'Foo'

s2 = "こんにちわ"

print(bytes(s2, "utf-8")) # b'\xe3\x81\x93\xe3\x82\x93\xe3\x81\xab\xe3\x81\xa1\xe3\x82\x8f'

バイト→文字列

str(byte, encoding)で変換可能

b = b'Foo'

s = str(b, 'UTF-8')
print(s) # 'Foo'


b2 = b'\xe3\x81\x93\xe3\x82\x93\xe3\x81\xab\xe3\x81\xa1\xe3\x82\x8f'

print(str(b2, "utf-8")) # こんにちわ

encode, decode関数を使用する

文字列→バイト

s = 'Foo'
 
b = s.encode('utf-8')
print(b) # b'Foo'


s2 = "こんにちわ"

print(a.encode("utf-8")) # b'\xe3\x81\x93\xe3\x82\x93\xe3\x81\xab\xe3\x81\xa1\xe3\x82\x8f'

バイト→文字列

b = b'Foo'

s = b.decode('UTF-8')
print(s) # 'Foo'

b2 = b'\xe3\x81\x93\xe3\x82\x93\xe3\x81\xab\xe3\x81\xa1\xe3\x82\x8f'

print(b2.decode("utf-8")) # こんにちわ

Base64エンコードとデコード

Base64

バイトデータを64種類(アルファベット小文字(a-z)26種類、大文字(A-Z)26種類、数値(0-9)10種類、記号(+,/)2種類)の文字とパディング用の”=”で表現するエンコード方式

エンコード

文字列をbase64の形式でエンコードするには、一度バイトデータに変換してから base64.b64encodeメソッドに渡す必要がある

import base64

# Basic認証で送信する認証情報
auth_info = "username:password"
encoded_auth_info = base64.b64encode(auth_info.encode("utf-8"))

print(encoded_auth_info) // b'dXNlcm5hbWU6cGFzc3dvcmQ=

なお、base64.b64encodeの結果はバイトデータなので、これを文字列で取得したい場合は以下のようにdecodeメソッドを使用する

print(encoded_auth_info.decode("utf-8")) # str型 dXNlcm5hbWU6cGFzc3dvcmQ=

デコード

Base64エンコードされたデータをエンコードしたい場合は、base64.b64decodeを使用する。このメソッドは引数にバイト型でも文字列型でもどちらでも受け取ることが可能。ただし返り値はいずれの場合もバイト型なので注意

byte型の場合

b64decodeの結果はバイト型

import base64

auth_info = "username:password"
encoded_auth_info = base64.b64encode(auth_info.encode("utf-8"))

#encoded_auth_infoはバイト型
decoded_auth_info = base64.b64decode(encoded_auth_info)
print(decoded_auth_info) # b'username:password'

文字列型の場合

文字列型の引数を受けても、返り値はバイト型

import base64

auth_info = "username:password"
encoded_auth_info = base64.b64encode(auth_info.encode("utf-8")).decode("utf-8")

#encoded_auth_infoは文字列型
decoded_auth_info = base64.b64decode(encoded_auth_info)
print(decoded_auth_info) # b'username:password'

具体的なケースで考える

Basic認証。クライアントから送信されたリクエストヘッダのAuthorizationというキーにbase64でエンコードされたユーザー名とパスワードが指定されていると想定する。それをデコードして検証する

import base64

# 送る側
auth_info = "username:password"

# base46形式でエンコードし、それを文字列型に変換
encoded_auth_info = base64.b64encode(auth_info.encode("utf-8")).decode("utf-8")

request={
    "header": {
            "Authorization": f"Basic {encoded_auth_info}"
    }
    
}

print(f"request: {request}") # {'header': {'Authorization': 'Basic dXNlcm5hbWU6cGFzc3dvcmQ='}}


# 受け取る側
sep = " "

# [Basic, エンコードされたusername:password]
splitted = request["header"]["Authorization"].split(sep)

encoded_auth_info = splitted[1]
print(f"encoded_auth_info: {encoded_auth_info}")# str型 dXNlcm5hbWU6cGFzc3dvcmQ=

decoded_auth_info = base64.b64decode(encoded_auth_info)
print(f"decoded_auth_info: {decoded_auth_info}") # b'username:password'
print(f"decoded_auth_info_str: {decoded_auth_info.decode('utf-8')}") # username:password


# 以下出力結果 ----------------------------------------------------------------------------
request: {'header': {'Authorization': 'Basic dXNlcm5hbWU6cGFzc3dvcmQ='}}
encoded_auth_info: dXNlcm5hbWU6cGFzc3dvcmQ=
decoded_auth_info: b'username:password'
decoded_auth_info_str: username:password

jsonエンコード、デコード

PythonオブジェクトからJSONへのエンコード(Jsonシリアライズ)

json.dumpsの引数に対象のオブジェクトを指定する。

import json

# 辞書→json
python_dict = {"name": "taro", "age": 11}
encoded = json.dumps(python_dict)
print(encoded) # '{"name": "taro", "age": 11}'

# 辞書→json(日本語を含む)
python_dict = {"name": "太郎", "age": 11}
encoded = json.dumps(python_dict)
print(encoded) # '{"name": "\u592a\u90ce", "age": 11}'


# 配列→json
python_list = ["太郎", "二郎", "三郎"]
encoded = json.dumps(python_list)
print(encoded) # '["\u592a\u90ce", "\u4e8c\u90ce", "\u4e09\u90ce"]'

注意点としては、基本型(str, int, float, bool, None)とdict, list, tupleのみ可能なので、それ以外の型のデータを引数にとると、Object of type 型名 is not JSON serializable というTypeErrorが生じる

# 配列→json(基本型以外を含む)
# python_list = [datetime.datetime.now()]
# encoded = json.dumps(python_list) # TypeError: Object of type datetime is not JSON serializable

# 以下のように日時オブジェクトではなく文字列としてであればOK
python_list = [datetime.datetime.now().strftime('%Y/%m/%d')]
encoded = json.dumps(python_list)
print(encoded) # '["2023/11/25"]'

JSON文字列をデコード(Jsonデシリアライズ)

json.loads()を使用する

import json

encoded = '{"name": "\u592a\u90ce", "age": 11}'
python_dict = json.loads(encoded)

print(python_dict) # {"name": "太郎", "age": 11}

まとめ

いかがでしたでしょうか。本記事では、Pythonでurl文字列をエンコード・デコードする方法について紹介しています。特にフレームワーク等を使わずにHTTPプロトコル通信を行う際には必須の知識となりますのでぜひ参考にしてみてください