json.dumpsのutf-8テキストを\ uエスケープシーケンスではなくUTF8として保存する


474

サンプルコード:

>>> import json
>>> json_string = json.dumps("ברי צקלה")
>>> print json_string
"\u05d1\u05e8\u05d9 \u05e6\u05e7\u05dc\u05d4"

問題:人間が読める形式ではありません。私の(スマートな)ユーザーは、JSONダンプを使用してテキストファイルを確認または編集することを望んでいます(XMLを使用したくありません)。

オブジェクトを(の代わりに\uXXXX)UTF-8 JSON文字列にシリアル化する方法はあり ますか?


9
+ forצקלה:)))
rubmz

回答:


642

ensure_ascii=Falseスイッチをjson.dumps()に使用し、値を手動でUTF-8にエンコードします。

>>> json_string = json.dumps("ברי צקלה", ensure_ascii=False).encode('utf8')
>>> json_string
b'"\xd7\x91\xd7\xa8\xd7\x99 \xd7\xa6\xd7\xa7\xd7\x9c\xd7\x94"'
>>> print(json_string.decode())
"ברי צקלה"

ファイルに書き込む場合はjson.dump()、次のコードを使用してファイルオブジェクトに任せます。

with open('filename', 'w', encoding='utf8') as json_file:
    json.dump("ברי צקלה", json_file, ensure_ascii=False)

Python 2に関する警告

Python 2の場合、考慮すべきいくつかの注意事項があります。これをファイルに書き込む場合は、io.open()ではなくを使用open()して、書き込み時にUnicode値をエンコードするファイルオブジェクトを生成し、json.dump()代わりにを使用してそのファイルに書き込むことができます。

with io.open('filename', 'w', encoding='utf8') as json_file:
    json.dump(u"ברי צקלה", json_file, ensure_ascii=False)

フラグがとオブジェクトの混合を生成する可能性があるjsonモジュールバグがあることに注意してください。Python 2の回避策は次のとおりです。ensure_ascii=Falseunicodestr

with io.open('filename', 'w', encoding='utf8') as json_file:
    data = json.dumps(u"ברי צקלה", ensure_ascii=False)
    # unicode(data) auto-decodes data to unicode if str
    json_file.write(unicode(data))

Python 2で、strUTF-8にエンコードされたバイト文字列(タイプ)を使用する場合は、encodingキーワードも設定してください。

>>> d={ 1: "ברי צקלה", 2: u"ברי צקלה" }
>>> d
{1: '\xd7\x91\xd7\xa8\xd7\x99 \xd7\xa6\xd7\xa7\xd7\x9c\xd7\x94', 2: u'\u05d1\u05e8\u05d9 \u05e6\u05e7\u05dc\u05d4'}

>>> s=json.dumps(d, ensure_ascii=False, encoding='utf8')
>>> s
u'{"1": "\u05d1\u05e8\u05d9 \u05e6\u05e7\u05dc\u05d4", "2": "\u05d1\u05e8\u05d9 \u05e6\u05e7\u05dc\u05d4"}'
>>> json.loads(s)['1']
u'\u05d1\u05e8\u05d9 \u05e6\u05e7\u05dc\u05d4'
>>> json.loads(s)['2']
u'\u05d1\u05e8\u05d9 \u05e6\u05e7\u05dc\u05d4'
>>> print json.loads(s)['1']
ברי צקלה
>>> print json.loads(s)['2']
ברי צקלה

72

ファイルに書き込むには

import codecs
import json

with codecs.open('your_file.txt', 'w', encoding='utf-8') as f:
    json.dump({"message":"xin chào việt nam"}, f, ensure_ascii=False)

stdoutに印刷するには

import json
print(json.dumps({"message":"xin chào việt nam"}, ensure_ascii=False))

1
SyntaxError:5行目のjson-utf8.pyファイルの非ASCII文字 '\ xc3'ですが、エンコードが宣言されていません。詳細については、python.org / dev / peps / pep
Alex

ありがとうございました!それがそんなに簡単であることに気づきませんでした。jsonに変換するデータが信頼できないユーザー入力である場合にのみ注意が必要です。
Karim Sonbol

@アレックスあなたはその問題を回避する方法を理解しましたか?
ガブリエルフェア

@Gabriel率直に言って、私は覚えていません。スニペットを脇に置くことはそれほど重要ではありませんでした:(
Alex

codecsライブラリを使用して私だけのために働いた。ありがとう!
igorkf

29

更新:これは間違った答えですが、なぜそれが間違っているのかを理解することは依然として役に立ちます。コメントを参照してください。

いかがunicode-escapeですか?

>>> d = {1: "ברי צקלה", 2: u"ברי צקלה"}
>>> json_str = json.dumps(d).decode('unicode-escape').encode('utf8')
>>> print json_str
{"1": "ברי צקלה", "2": "ברי צקלה"}

9
unicode-escape必要ありませんjson.dumps(d, ensure_ascii=False).encode('utf8')。代わりに使用できます。そして、json がすべてのケースでPythonのコーデックとまったく同じルールを使用することは保証されません。つまり、一部のケースでは結果が同じである場合とそうでない場合があります。反対票は、不必要でおそらく間違った変換のためのものです。無関係:utf8ロケール、またはenvvarがここでutf8を指定している場合にのみ機能します(代わりにUnicodeを出力します)。unicode-escapeprint json_strPYTHONIOENCODING
jfs

3
別の問題:文字列値の二重引用符はエスケープを失うため、JSON出力破損します
Martijn Pieters

Python3のエラー:AttributeError: 'str' object has no attribute 'decode'
Gank

1
ユニコードエスケープは正常に動作します!私はこの答えを正しいものとして受け入れます。
労働者

@jfsいいえ、json.dumps(d, ensure_ascii=False).encode('utf8')少なくとも私にとっては機能しません。UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position ...エラーが発生します。unicode-escapeただし、バリアントは正常に機能します。
18年

24

Petersのpython 2回避策は、エッジケースで失敗します。

d = {u'keyword': u'bad credit  \xe7redit cards'}
with io.open('filename', 'w', encoding='utf8') as json_file:
    data = json.dumps(d, ensure_ascii=False).decode('utf8')
    try:
        json_file.write(data)
    except TypeError:
        # Decode data to Unicode first
        json_file.write(data.decode('utf8'))

UnicodeEncodeError: 'ascii' codec can't encode character u'\xe7' in position 25: ordinal not in range(128)

3行目の.decode( 'utf8')の部分でクラッシュしていました。その手順とasciiの特別な大文字小文字の区別を回避することでプログラムを大幅に簡素化することで問題を修正しました。

with io.open('filename', 'w', encoding='utf8') as json_file:
  data = json.dumps(d, ensure_ascii=False, encoding='utf8')
  json_file.write(unicode(data))

cat filename
{"keyword": "bad credit  çredit cards"}

2
「エッジケース」は、単に私の側でテストされていないばかげたエラーでした。あなたのunicode(data)アプローチは、むしろ例外処理を使用してより良いオプションです。encoding='utf8'キーワード引数は、json.dumps()生成される出力とは関係がないことに注意してください。関数が受け取るstr入力のデコードに使用されます。
Martijn Pieters

2
@MartijnPieters:またはより簡単:(asciiのみの)strまたはunicodeオブジェクトを返すopen('filename', 'wb').write(json.dumps(d, ensure_ascii=False).encode('utf8'))かどうかに関係dumpsなく機能します。
jfs 2015

@JFSebastian:はい、暗黙的に最初にstr.encode('utf8') デコードするためです。ただしunicode(data)strオブジェクトが指定されている場合は、も同様です。:-)を使用io.open()すると、BOMを書き込むコーデックを使用するなど、より多くのオプションが提供され、JSONデータを別の方法でフォローします。
Martijn Pieters

@MartijnPieters:.encode('utf8')ベースのバリアントはPython 2と3の両方で機能します(同じコード)。unicodePython 3にはありません。無関係:jsonファイルはBOMを使用しないでください(jsonパーサーを確認するとBOMが無視される場合があります。エラーレート3983を参照してください)。
jfs

追加encoding='utf8'json.dumpsて問題を解決します。PS私はキリル文字のテキストをダンプします
Max L

8

Python 3.7以降、次のコードは正常に動作します。

from json import dumps
result = {"symbol": "ƒ"}
json_string = dumps(result, sort_keys=True, indent=2, ensure_ascii=False)
print(json_string)

出力:

{"symbol": "ƒ"}

2
python 3.6(検証済み)でも。
ベリーTsakala

7

以下は、上記の理解とgoogleを読んだ私の理解です。

# coding:utf-8
r"""
@update: 2017-01-09 14:44:39
@explain: str, unicode, bytes in python2to3
    #python2 UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 7: ordinal not in range(128)
    #1.reload
    #importlib,sys
    #importlib.reload(sys)
    #sys.setdefaultencoding('utf-8') #python3 don't have this attribute.
    #not suggest even in python2 #see:http://stackoverflow.com/questions/3828723/why-should-we-not-use-sys-setdefaultencodingutf-8-in-a-py-script
    #2.overwrite /usr/lib/python2.7/sitecustomize.py or (sitecustomize.py and PYTHONPATH=".:$PYTHONPATH" python)
    #too complex
    #3.control by your own (best)
    #==> all string must be unicode like python3 (u'xx'|b'xx'.encode('utf-8')) (unicode 's disappeared in python3)
    #see: http://blog.ernest.me/post/python-setdefaultencoding-unicode-bytes

    #how to Saving utf-8 texts in json.dumps as UTF8, not as \u escape sequence
    #http://stackoverflow.com/questions/18337407/saving-utf-8-texts-in-json-dumps-as-utf8-not-as-u-escape-sequence
"""

from __future__ import print_function
import json

a = {"b": u"中文"}  # add u for python2 compatibility
print('%r' % a)
print('%r' % json.dumps(a))
print('%r' % (json.dumps(a).encode('utf8')))
a = {"b": u"中文"}
print('%r' % json.dumps(a, ensure_ascii=False))
print('%r' % (json.dumps(a, ensure_ascii=False).encode('utf8')))
# print(a.encode('utf8')) #AttributeError: 'dict' object has no attribute 'encode'
print('')

# python2:bytes=str; python3:bytes
b = a['b'].encode('utf-8')
print('%r' % b)
print('%r' % b.decode("utf-8"))
print('')

# python2:unicode; python3:str=unicode
c = b.decode('utf-8')
print('%r' % c)
print('%r' % c.encode('utf-8'))
"""
#python2
{'b': u'\u4e2d\u6587'}
'{"b": "\\u4e2d\\u6587"}'
'{"b": "\\u4e2d\\u6587"}'
u'{"b": "\u4e2d\u6587"}'
'{"b": "\xe4\xb8\xad\xe6\x96\x87"}'

'\xe4\xb8\xad\xe6\x96\x87'
u'\u4e2d\u6587'

u'\u4e2d\u6587'
'\xe4\xb8\xad\xe6\x96\x87'

#python3
{'b': '中文'}
'{"b": "\\u4e2d\\u6587"}'
b'{"b": "\\u4e2d\\u6587"}'
'{"b": "中文"}'
b'{"b": "\xe4\xb8\xad\xe6\x96\x87"}'

b'\xe4\xb8\xad\xe6\x96\x87'
'中文'

'中文'
b'\xe4\xb8\xad\xe6\x96\x87'
"""

5

json.dump()を使用した私の解決策は次のとおりです。

def jsonWrite(p, pyobj, ensure_ascii=False, encoding=SYSTEM_ENCODING, **kwargs):
    with codecs.open(p, 'wb', 'utf_8') as fileobj:
        json.dump(pyobj, fileobj, ensure_ascii=ensure_ascii,encoding=encoding, **kwargs)

ここで、SYSTEM_ENCODINGは次のように設定されています。

locale.setlocale(locale.LC_ALL, '')
SYSTEM_ENCODING = locale.getlocale()[1]

4

可能であればコーデックを使用し、

with codecs.open('file_path', 'a+', 'utf-8') as fp:
    fp.write(json.dumps(res, ensure_ascii=False))

1

ここで元の答えをありがとう。python 3次のコード行:

print(json.dumps(result_dict,ensure_ascii=False))

大丈夫だった。必須でない場合は、コードにテキストを書きすぎないようにしてください。

これはpythonコンソールには十分かもしれません。ただし、サーバーを満足させるには、ここで説明されているようにロケールを設定する必要がある場合があります(apache2の場合) http://blog.dscpl.com.au/2014/09/setting-lang-and-lcall-when-using .html

基本的にhebunにhe_ILまたは任意の言語ロケールをインストールします。インストールされていないことを確認してください

locale -a 

XXがあなたの言語であるところにそれをインストールしてください

sudo apt-get install language-pack-XX

例えば:

sudo apt-get install language-pack-he

/ etc / apache2 / envvrsに次のテキストを追加します

export LANG='he_IL.UTF-8'
export LC_ALL='he_IL.UTF-8'

あなたがうまくいけば、次のようなApacheからPythonエラーが発生しないでしょう:

print(js)UnicodeEncodeError: 'ascii' codec ca n't encode characters in position 41-45:ordinal not range(128)

また、Apache では、ここで説明するように、utfをデフォルトのエンコーディングにしてみてください
。ApacheのデフォルトのエンコーディングをUTF-8に変更する方法

apacheエラーはデバッグするのが面倒な場合があり、誤ってそれがpythonからのものであると誤って考える可能性があるため、早期に実行してください。


1

ファイルとファイルコンテンツのアラビア語テキストからJSON文字列をロードする場合。その後、これは機能します。

次のようなファイルを想定:arabic.json

{ 
"key1" : "لمستخدمين",
"key2" : "إضافة مستخدم"
}

arabic.jsonファイルからアラビア語のコンテンツを取得する

with open(arabic.json, encoding='utf-8') as f:
   # deserialises it
   json_data = json.load(f)
   f.close()


# json formatted string
json_data2 = json.dumps(json_data, ensure_ascii = False)

DjangoテンプレートでJSONデータを使用するには、以下の手順に従います。

# If have to get the JSON index in Django Template file, then simply decode the encoded string.

json.JSONDecoder().decode(json_data2)

できた!これで、アラビア語の値を持つJSONインデックスとして結果を取得できます。


fh.close() fh未定義です。
AMC

ITが修正されました。それは次のようになりますf.close()
チャンダン・シャルマ

0

Unicodeエスケープを使用して問題を解決する

>>>import json
>>>json_string = json.dumps("ברי צקלה")
>>>json_string.encode('ascii').decode('unicode-escape')
'"ברי צקלה"'

説明する

>>>s = '漢  χαν  хан'
>>>print('unicode: ' + s.encode('unicode-escape').decode('utf-8'))
unicode: \u6f22  \u03c7\u03b1\u03bd  \u0445\u0430\u043d

>>>u = s.encode('unicode-escape').decode('utf-8')
>>>print('original: ' + u.encode("utf-8").decode('unicode-escape'))
original:   χαν  хан

元のリソース:https : //blog.csdn.net/chuatony/article/details/72628868


-3

Martijnが指摘したように、json.dumpsでEnsure_ascii = Falseを使用することがこの問題を解決する正しい方向です。ただし、これにより例外が発生する場合があります。

UnicodeDecodeError: 'ascii' codec can't decode byte 0xe7 in position 1: ordinal not in range(128)

sys.getdefaultencoding()を正しく設定するには、site.pyまたはsitecustomize.pyで追加の設定が必要です。site.pyはlib / python2.7 /の下にあり、sitecustomize.pyはlib / python2.7 / site-packagesの下にあります。

site.pyを使用する場合は、def setencoding()で最初のif 0:をif 1:に変更して、Pythonがオペレーティングシステムのロケールを使用するようにします。

sitecustomize.pyを使用したい場合は、作成していないと存在しない可能性があります。単にこれらの行を入れてください:

import sys
reload(sys)
sys.setdefaultencoding('utf-8')

次に、以下のようなutf-8形式で中国語のjson出力を実行できます。

name = {"last_name": u"王"}
json.dumps(name, ensure_ascii=False)

\ uエスケープされたjson文字列ではなく、utf-8エンコードされた文字列を取得します。

デフォルトのエンコーディングを確認するには:

print sys.getdefaultencoding()

「utf-8」または「UTF-8」を取得して、site.pyまたはsitecustomize.pyの設定を確認してください。

対話型のPythonコンソールではsys.setdefaultencoding( "utf-8")を実行できないことに注意してください。


2
番号。しないでください。デフォルトの文字エンコードを変更するとは何の関係もありませんjsons「をensure_ascii=False。そうでない場合は、最小限の完全なコード例を提供してください。
jfs 2014年

この例外が発生するのは、ASCII以外のバイト文字列(Unicode値ではないなど)をフィードするか、結果のJSON値(Unicode文字列)をASCII以外のバイト文字列と組み合わせようとした場合のみです。文字列データを適切に管理していない場合、デフォルトのエンコーディングをUTF-8に設定すると、基本的に問題が隠されます。
Martijn Pieters
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.