python でエスケープ文字の入った JSON からコンテンツを復元する


MIME データを JSON に格納したら復元に戸惑った話。


# 背景

```
import json
import base64
import os
import sys

filepath = sys.argv[1]
filename = os.path.basename(filepath)
# 拡張子を取得
type = os.path.splitext(filename)[1][1:]


data = {}
with open(filepath, mode='rb') as file:
    img = file.read()
data['type'] = type
data['filename'] = filename
data['file'] = base64.encodebytes(img).decode('utf-8')
```

として、
```
print(data['file'])
```

とすると、

```
UEsDBBQAAAgAADAl71afAy7EKwAAACsAAAAIAAAAbWltZXR5cGVhcHBsaWNhdGlvbi92bmQub2Fz
aXMub3BlbmRvY3VtZW50LmdyYXBoaWNzUEsDBBQAAAgAADAl71YAAAAAAAAAAAAAAAAcAAAAQ29u
ZmlndXJhdGlvbnMyL2FjY2VsZXJhdG9yL1BLAwQUAAAIAAAwJe9WAAAAAAAAAAAAAAAAHwAAAENv
bmZpZ3VyYXRpb25zMi9pbWFnZXMvQml0bWFwcy9QSwMEFAAACAAAMCXvVgAAAAAAAAAAAAAAABoA
AABDb25maWd1cmF0aW9uczIvdG9vbHBhbmVsL1BLAwQUAAAIAAAwJe9WAAAAAAAAAAAAAAAAHAAA
AENvbmZpZ3VyYXRpb25zMi9wcm9ncmVzc2Jhci9QSwMEFAAACAAAMCXvVgAAAAAAAAAAAAAAABoA
AABDb25maWd1cmF0aW9uczIvc3RhdHVzYmFyL1BLAwQUAAAIAAAwJe9WAAAAAAAAAAAAAAAAGAAA
```

のようになる。これは、base64.encodebytes(s) によって RFC2045 (MIME) に従った 76 文字ごとに改行されたもの。


```
print(jsonobject["file"])
```

とすると
```
UEsDBBQAAAgAADAl71afAy7EKwAAACsAAAAIAAAAbWltZXR5cGVhcHBsaWNhdGlvbi92bmQub2Fz\n
aXMub3BlbmRvY3VtZW50LmdyYXBoaWNzUEsDBBQAAAgAADAl71YAAAAAAAAAAAAAAAAcAAAAQ29u\n
ZmlndXJhdGlvbnMyL2FjY2VsZXJhdG9yL1BLAwQUAAAIAAAwJe9WAAAAAAAAAAAAAAAAHwAAAENv\n
bmZpZ3VyYXRpb25zMi9pbWFnZXMvQml0bWFwcy9QSwMEFAAACAAAMCXvVgAAAAAAAAAAAAAAABoA\n
AABDb25maWd1cmF0aW9uczIvdG9vbHBhbmVsL1BLAwQUAAAIAAAwJe9WAAAAAAAAAAAAAAAAHAAA\n
AENvbmZpZ3VyYXRpb25zMi9wcm9ncmVzc2Jhci9QSwMEFAAACAAAMCXvVgAAAAAAAAAAAAAAABoA\n
.
.
.
```
となった(わかりやすいように\nの後ろに改行を入れているが、実際は巨大な1行となっている)。

これは、JSONの規格で改行を入れることができないために改行がエスケープされている。

そのうえで、 

```

print(json.dumps(data))

```
として、以下のように出力されたものを使ってデータ交換を行う。
```
(b'tEXt', b'{"type": "odg", "filename": "x2.odg", "file":"
UEsDBBQAAAgAADAl71afAy7EKwAAACsAAAAIAAAAbWltZXR5cGVhcHBsaWNhdGlvbi92bmQub2Fz\\n
aXMub3BlbmRvY3VtZW50LmdyYXBoaWNzUEsDBBQAAAgAADAl71YAAAAAAAAAAAAAAAAcAAAAQ29u\\n
ZmlndXJhdGlvbnMyL2FjY2VsZXJhdG9yL1BLAwQUAAAIAAAwJe9WAAAAAAAAAAAAAAAAHwAAAENv\\n
bmZpZ3VyYXRpb25zMi9pbWFnZXMvQml0bWFwcy9QSwMEFAAACAAAMCXvVgAAAAAAAAAAAAAAABoA\\n
AABDb25maWd1cmF0aW9uczIvdG9vbHBhbmVsL1BLAwQUAAAIAAAwJe9WAAAAAAAAAAAAAAAAHAAA\\n
AENvbmZpZ3VyYXRpb25zMi9wcm9ncmVzc2Jhci9QSwMEFAAACAAAMCXvVgAAAAAAAAAAAAAAABoA\\n
.
.
.
```

さて、JSONデータを受け取った方はどうしたら RFC2045 (MIME) に従った 76 文字ごとに改行されたものに復元できるかな?

# 解決方法
```
print(jsonobject["file"].encode("utf-8").decode("unicode-escape")) 
```

得られるもの

```
UEsDBBQAAAgAADAl71afAy7EKwAAACsAAAAIAAAAbWltZXR5cGVhcHBsaWNhdGlvbi92bmQub2Fz
aXMub3BlbmRvY3VtZW50LmdyYXBoaWNzUEsDBBQAAAgAADAl71YAAAAAAAAAAAAAAAAcAAAAQ29u
ZmlndXJhdGlvbnMyL2FjY2VsZXJhdG9yL1BLAwQUAAAIAAAwJe9WAAAAAAAAAAAAAAAAHwAAAENv
bmZpZ3VyYXRpb25zMi9pbWFnZXMvQml0bWFwcy9QSwMEFAAACAAAMCXvVgAAAAAAAAAAAAAAABoA
AABDb25maWd1cmF0aW9uczIvdG9vbHBhbmVsL1BLAwQUAAAIAAAwJe9WAAAAAAAAAAAAAAAAHAAA
AENvbmZpZ3VyYXRpb25zMi9wcm9ncmVzc2Jhci9QSwMEFAAACAAAMCXvVgAAAAAAAAAAAAAAABoA
AABDb25maWd1cmF0aW9uczIvc3RhdHVzYmFyL1BLAwQUAAAIAAAwJe9WAAAAAAAAAAAAAAAAGAAA
AENvbmZpZ3VyYXRpb25zMi90b29sYmFyL1BLAwQUAAAIAAAwJe9WAAAAAAAAAAAAAAAAGAAAAENv
bmZpZ3VyYXRpb25zMi9mbG9hdGVyL1BLAwQUAAAIAAAwJe9WAAAAAAAAAAAAAAAAGgAAAENvbmZp
.
.
.

```

python3  は信号処理してるとムダな encode や decode が重奏して頭が痒くなりますね。