thirose’s blog

openstackやpythonなどなど

python で json.loads() したときに 特定の制御文字列が入ってるとJSONDecodeErrorが返ってくる

問題

今回は以下のような文字列を json.loads() してみたときにおきた問題があったときの対応をまとめました。

sample_text = '{"key": "value \t value"}'

再現させる

>>> import json
>>> sample_text = '{"key": "value \t value"}'
>>>
>>> json.loads(sample_text)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/www/.pyenv/versions/3.6.5/lib/python3.6/json/__init__.py", line 354, in loads
    return _default_decoder.decode(s)
  File "/home/www/.pyenv/versions/3.6.5/lib/python3.6/json/decoder.py", line 339, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/home/www/.pyenv/versions/3.6.5/lib/python3.6/json/decoder.py", line 355, in raw_decode
    obj, end = self.scan_once(s, idx)
json.decoder.JSONDecodeError: Invalid control character at: line 1 column 16 (char 15)

問題は、 valueに入っている \t が入っていることが原因のようです。
以下 json moduleのドキュメントを読んでわかる通り、

strict が false (デフォルトは True) の場合、制御文字を文字列に含めることができます。ここで言う制御文字とは、'\t' (タブ)、'\n'、'\r'、'\0' を含む 0-31 の範囲のコードを持つ文字のことです。

json --- JSON エンコーダおよびデコーダ — Python 3.7.6 ドキュメント
との記述があります。

ということは、strictがTrue(default value)だった場合には含めることができないです。

解決策

>>> json.loads(sample_text, strict=False)
{'key': 'value \t value'}

引数をデフォルトの true から false に変更すればjson loadsできるようになります。 ということで、defaultが True の値を False に設定してあげれば、json.laods()できるようになります。 Decoderのobjectには他にも以下のように引数もあります。

class json.JSONDecoder(*, object_hook=None, parse_float=None, parse_int=None, parse_constant=None, strict=True, object_pairs_hook=None)

入門 Python 3

入門 Python 3