Как получить строковые объекты вместо Unicode из JSON?
Я использую Python 2 для разбора JSON из кодировка ASCII текстовые файлы.
при загрузке этих файлов с помощью либо json
или simplejson
, все мои строковые значения приводятся к объектам Unicode вместо строковых объектов. Проблема в том, что я должен использовать данные с некоторыми библиотеками, которые принимают только строковые объекты. Я!--14-->невозможно изменить библиотеки и не обновлять их.
можно ли получить строковые объекты вместо Unicode?
пример
>>> import json
>>> original_list = ['a', 'b']
>>> json_list = json.dumps(original_list)
>>> json_list
'["a", "b"]'
>>> new_list = json.loads(json_list)
>>> new_list
[u'a', u'b'] # I want these to be of type `str`, not `unicode`
обновление
этот вопрос был задан давным-давно, когда я застрял с Python 2. Одним из простых и чистых решений на сегодня является использование последней версии Python-т. е. Python 3 и вперед.
21 ответов
решение object_hook
import json
def json_load_byteified(file_handle):
return _byteify(
json.load(file_handle, object_hook=_byteify),
ignore_dicts=True
)
def json_loads_byteified(json_text):
return _byteify(
json.loads(json_text, object_hook=_byteify),
ignore_dicts=True
)
def _byteify(data, ignore_dicts = False):
# if this is a unicode string, return its string representation
if isinstance(data, unicode):
return data.encode('utf-8')
# if this is a list of values, return list of byteified values
if isinstance(data, list):
return [ _byteify(item, ignore_dicts=True) for item in data ]
# if this is a dictionary, return dictionary of byteified keys and values
# but only if we haven't already byteified it
if isinstance(data, dict) and not ignore_dicts:
return {
_byteify(key, ignore_dicts=True): _byteify(value, ignore_dicts=True)
for key, value in data.iteritems()
}
# if it's anything else, return it in its original form
return data
пример использования:
>>> json_loads_byteified('{"Hello": "World"}')
{'Hello': 'World'}
>>> json_loads_byteified('"I am a top-level string"')
'I am a top-level string'
>>> json_loads_byteified('7')
7
>>> json_loads_byteified('["I am inside a list"]')
['I am inside a list']
>>> json_loads_byteified('[[[[[[[["I am inside a big nest of lists"]]]]]]]]')
[[[[[[[['I am inside a big nest of lists']]]]]]]]
>>> json_loads_byteified('{"foo": "bar", "things": [7, {"qux": "baz", "moo": {"cow": ["milk"]}}]}')
{'things': [7, {'qux': 'baz', 'moo': {'cow': ['milk']}}], 'foo': 'bar'}
>>> json_load_byteified(open('somefile.json'))
{'more json': 'from a file'}
как это работает и почему я должен его использовать?
функция Марка Эмери короче и яснее, чем эти, так в чем же их смысл? Зачем тебе их использовать?
чисто производительность. Ответ Марка декодирует текст JSON, полностью с первых строк в кодировке Юникод, затем повторяется через всю декодированное значение преобразуйте все строки в байтовые строки. Это имеет несколько нежелательных эффектов:
- копия всей декодированной структуры создается в памяти
- если ваш объект JSON действительно глубоко вложенные (500 уровней или более), то вы нажмете максимальную глубину рекурсии Python
этот ответ смягчает обе эти проблемы с производительностью, используя . Эта функция может использоваться для реализации пользовательских декодеров
так как словари вложенных много уровней глубоко в других словарях получить переданы в object_hook
как они декодируются, мы можем byteify любые строки или списки внутри них при этом точки и избежать глубокой рекурсии позже.
object_hook
как она стоит, потому что повторяется во вложенные словари. Мы предотвращаем эту рекурсию в этом ответе с помощью до _byteify
, который передается ему во все времена за исключением, когда object_hook
передает ему новый dict
для byteify. The ignore_dicts
флаг говорит _byteify
игнорировать dict
s, так как они уже были byteified.
наконец, наши реализации json_load_byteified
и json_loads_byteified
вызов _byteify
(С ignore_dicts=True
) о результате, возвращенном из json.load
или json.loads
для обработки случая, когда декодируемый текст JSON не имеет dict
на верхнем уровне.
в то время как есть некоторые хорошие ответы здесь, я закончил с помощью PyYAML для разбора моих файлов JSON, так как он дает ключи и значения как str
введите строки вместо unicode
тип. Поскольку JSON является подмножеством YAML, он отлично работает:
>>> import json
>>> import yaml
>>> list_org = ['a', 'b']
>>> list_dump = json.dumps(list_org)
>>> list_dump
'["a", "b"]'
>>> json.loads(list_dump)
[u'a', u'b']
>>> yaml.safe_load(list_dump)
['a', 'b']
Примечания
некоторые вещи, чтобы отметить хотя:
Я string объекты потому что все мои записи кодировка ASCII. Если бы я использовал кодировку unicode записи, я бы вернул их как объекты unicode - нет преобразования!
вы должны (наверное, всегда) использовать PyYAML это
safe_load
функция; если вы используете его для загрузки файлов JSON, вам не нужна "дополнительная мощность"load
в любом случае функция.если вы хотите парсер YAML, который имеет больше поддержки версии 1.2 спецификации (и правильно анализирует очень низкие числа) попробовать Ruamel И YAML:
pip install ruamel.yaml
иimport ruamel.yaml as yaml
все, что мне нужно в моих тестах.
преобразование
как указано, нет никакого преобразования! Если вы не можете быть уверены, что имеете дело только со значениями ASCII (и вы не можете быть уверены большую часть времени), лучше используйте функции преобразования:
я использовал один из Марк Амеры пару раз сейчас он отлично работает и очень прост в использовании. Вы также можете использовать аналогичную функцию как object_hook
вместо этого, поскольку это может повысить производительность больших файлов. См. немного более вовлеченный ответ от Miskuf Mirec для этого.
нет встроенной опции, чтобы функции модуля json возвращали байтовые строки вместо строк unicode. Однако эта короткая и простая рекурсивная функция преобразует любой декодированный объект JSON из строк unicode в строки байтов UTF-8:
def byteify(input):
if isinstance(input, dict):
return {byteify(key): byteify(value)
for key, value in input.iteritems()}
elif isinstance(input, list):
return [byteify(element) for element in input]
elif isinstance(input, unicode):
return input.encode('utf-8')
else:
return input
просто вызовите это на выходе, который вы получаете от json.load
или json.loads
звонок.
пара замечаний:
- для поддержки Python 2.6 или более ранней версии замените
return {byteify(key): byteify(value) for key, value in input.iteritems()}
Сreturn dict([(byteify(key), byteify(value)) for key, value in input.iteritems()])
, С словарные понимания не поддерживались до Python 2.7. - поскольку этот ответ повторяется через всю декодируются объект, он имеет несколько нежелательных характеристик, которые можно избежать при очень аккуратном использовании
object_hook
илиobject_pairs_hook
параметры. ответ Мирека Мискуфа пока единственный, кому удается это сделать правильно, хотя, как следствие, это значительно сложнее, чем мой подход.
можно использовать на json.loads
пройти в конвертере. Вам не нужно делать преобразование после факта. The json
модуль всегда будет передавать object_hook
только дикты, и он будет рекурсивно проходить во вложенных диктах, поэтому вам не нужно рекурсировать во вложенные дикты самостоятельно. Я не думаю, что я бы преобразовал строки unicode в числа, такие как шоу Уэллса. Если это строка unicode, она была указана как строка в файле JSON, поэтому она должна быть строкой (или файл плохой).
кроме того, я бы постарался избежать чего-то вроде str(val)
на
это потому, что json не имеет разницы между строковыми объектами и объектами unicode. Они все строки в javascript.
Я думаю JSON имеет право возвращать объекты unicode. На самом деле, я бы не принял ничего меньшего, так как javascript strings на самом деле unicode
объекты (т. е. строки JSON (javascript) могут хранить любой символа Юникода), поэтому имеет смысл создать unicode
объекты при переводе строк из JSON. Простой строки просто не подходят, так как библиотека должна угадать кодировку, которую вы хотите.
лучше использовать unicode
string объекты везде. Поэтому лучше всего обновить библиотеки, чтобы они могли работать с объектами unicode.
но если вы действительно хотите bytestrings, просто Закодируйте результаты в кодировку по вашему выбору:
>>> nl = json.loads(js)
>>> nl
[u'a', u'b']
>>> nl = [s.encode('utf-8') for s in nl]
>>> nl
['a', 'b']
существует простой обходной путь.
TL; DR-Use ast.literal_eval()
вместо json.loads()
. Оба!--4--> и json
в стандартной библиотеке.
хотя это не "идеальный" ответ, он получает один довольно далеко, если ваш план состоит в том, чтобы полностью игнорировать Unicode. В Python 2.7
import json, ast
d = { 'field' : 'value' }
print "JSON Fail: ", json.loads(json.dumps(d))
print "AST Win:", ast.literal_eval(json.dumps(d))
выдает:
JSON Fail: {u'field': u'value'}
AST Win: {'field': 'value'}
это становится более волосатым, когда некоторые объекты действительно строки Unicode. Полный ответ быстро становится волосатым.
Я боюсь, что нет способа достичь этого автоматически в библиотеке simplejson.
сканер и декодер в simplejson предназначены для создания текста unicode. Для этого библиотека использует функцию c_scanstring
(если он доступен, для скорости), или py_scanstring
если версия C недоступна. The scanstring
функция вызывается несколько раз почти каждой процедурой, которую simplejson имеет для декодирования структуры, которая может содержать текст. Вам придется либо monkeypatch the scanstring
значение в simplejson.декодер, или подкласс JSONDecoder
и предоставить практически всю собственную реализацию всего, что может содержать текст.
причина, по которой simplejson выводит unicode, заключается в том, что в JSON спецификации в частности, упоминается, что"строка представляет собой набор нулевых или более символов Юникода"... поддержка unicode предполагается как часть самого формата. Пакет это scanstring
реализация идет так далеко, чтобы сканировать и интерпретировать unicode escapes (даже проверка ошибок для искаженных многобайтовых представлений кодировок), поэтому единственный способ надежно вернуть вам значение-это unicode.
если у вас есть старая библиотека, которая нуждается в str
, Я рекомендую вам либо тщательно искать вложенную структуру данных после синтаксического анализа (что я признаю, что вы явно сказали, что хотите избежать... извините), или, возможно, оберните свои библиотеки в какой-то фасад, где вы можете массировать входные параметры на более гранулированный уровень. Второй подход может быть более управляемым, чем первый, если ваши структуры данных действительно глубоко вложенные.
ответ Майка Бреннана близко, но нет причин повторно пересекать всю структуру. Если вы используете object_hook_pairs
(Python 2.7+) параметр:
object_pairs_hook
- необязательная функция, которая будет вызываться в результате декодирования любого объектного литерала с упорядоченным списком пар. Возвращаемое значениеobject_pairs_hook
будет использоваться вместоdict
. Эту функцию можно использовать для реализации custom декодеры, которые полагаются на порядок декодирования пар ключей и значений (например,collections.OrderedDict
запомнит порядок вставки). Еслиobject_hook
также определено,object_pairs_hook
имеет приоритет.
С ним вы получаете каждый объект JSON, переданный вам, поэтому вы можете выполнять декодирование без необходимости рекурсии:
def deunicodify_hook(pairs):
new_pairs = []
for key, value in pairs:
if isinstance(value, unicode):
value = value.encode('utf-8')
if isinstance(key, unicode):
key = key.encode('utf-8')
new_pairs.append((key, value))
return dict(new_pairs)
In [52]: open('test.json').read()
Out[52]: '{"1": "hello", "abc": [1, 2, 3], "def": {"hi": "mom"}, "boo": [1, "hi", "moo", {"5": "some"}]}'
In [53]: json.load(open('test.json'))
Out[53]:
{u'1': u'hello',
u'abc': [1, 2, 3],
u'boo': [1, u'hi', u'moo', {u'5': u'some'}],
u'def': {u'hi': u'mom'}}
In [54]: json.load(open('test.json'), object_pairs_hook=deunicodify_hook)
Out[54]:
{'1': 'hello',
'abc': [1, 2, 3],
'boo': [1, 'hi', 'moo', {'5': 'some'}],
'def': {'hi': 'mom'}}
обратите внимание, что мне никогда не нужно вызывать крюк рекурсивно, так как каждый объект будет передан крюку, когда вы используете object_pairs_hook
. Вам нужно заботиться о списках, но, как вы можете видеть, объект в списке будет правильно преобразован, и вам не нужно рекурсировать, чтобы это произошло.
EDIT: сотрудник указал, что Python2.6 не имеет object_hook_pairs
. Вы все еще можете использовать эту волю Python2.6. сделав очень небольшое изменение. В крючке выше измените:
for key, value in pairs:
to
for key, value in pairs.iteritems():
затем использовать object_hook
вместо object_pairs_hook
:
In [66]: json.load(open('test.json'), object_hook=deunicodify_hook)
Out[66]:
{'1': 'hello',
'abc': [1, 2, 3],
'boo': [1, 'hi', 'moo', {'5': 'some'}],
'def': {'hi': 'mom'}}
используя object_pairs_hook
приводит к созданию одного экземпляра словаря меньше для каждого объекта в объекте JSON, который, если вы разбираете огромный документ, может стоить того.
Как Марк (Эмери) правильно отмечает: использование PyYamlдесериализатор на дампе json работает только в том случае, если у вас есть только ASCII. По крайней мере из коробки.
два кратких комментария к подходу PyYaml:
никогда используйте yaml.загрузка данных из поля. Его особенность(!) yaml для выполнения произвольного кода, скрытого в структуре.
-
вы можете сделайте его работать также для non ASCII через это:
def to_utf8(loader, node): return loader.construct_scalar(node).encode('utf-8') yaml.add_constructor(u'tag:yaml.org,2002:str', to_utf8)
но производительность мудрая его никакого сравнения с ответом Марка Эмери:
бросая некоторые глубоко вложенные примеры диктов на два метода, я получаю это (с DT[j] = Time delta of json.нагрузок(в формате JSON.dumps (m))):
dt[yaml.safe_load(json.dumps(m))] =~ 100 * dt[j]
dt[byteify recursion(Mark Amery)] =~ 5 * dt[j]
Итак, десериализация, включая полную прогулку по дереву и кодирование, хорошо в пределах порядка величины реализации json на основе C. Я нахожу это удивительно быстрым, а также более надежным чем нагрузка yaml на глубоко вложенные структуры. И менее подвержен ошибкам безопасности, глядя на yaml.нагрузка.
=> в то время как я был бы признателен за указатель на C только на основе преобразователя функция byteify должен быть ответ по умолчанию.
это особенно верно, если ваша структура json из поля, содержащего пользовательский ввод. Потому что тогда вам, вероятно, нужно ходить в любом случае над вашей структурой-независимый на ваших пожеланных внутренних данных структуры (только "сэндвич Юникода" или байтовые строки).
почему?
Unicode нормализация. Для неосознанных: возьмите болеутоляющее и прочитайте этой.
таким образом, используя рекурсию byteify, вы убиваете двух птиц одним камнем:
- получите свои bytestrings из вложенных дампов json
- получить значения ввода пользователя нормализованы, так что вы найдете материал в вашем хранилище.
в моих тестах оказалось это замена входа.кодирование ('utf-8') с помощью unicodedata.нормализовать ('NFC', вход).кодирование ("utf-8") было даже быстрее, чем без NFC, но это сильно зависит от выборочных данных, я думаю.
попался, что simplejson
и json
- это два разных модуля, по крайней мере, в том, как они имеют дело с unicode. У вас есть json
в py 2.6+, и это дает вам значения unicode, тогда как simplejson
возвращает строковые объекты. Просто попробуйте easy_install-ING simplejson в вашей среде и посмотрите, работает ли это. Для меня-да.
Итак, я столкнулся с той же проблемой. Угадайте, каким был первый результат Google.
поскольку мне нужно передать все данные PyGTK, строки unicode мне тоже не очень полезны. Итак, у меня есть другой метод рекурсивного преобразования. На самом деле это также необходимо для преобразования typesafe JSON - json.dump () будет бросать любые не-литералы, такие как объекты Python. Однако не преобразует индексы dict.
# removes any objects, turns unicode back into str
def filter_data(obj):
if type(obj) in (int, float, str, bool):
return obj
elif type(obj) == unicode:
return str(obj)
elif type(obj) in (list, tuple, set):
obj = list(obj)
for i,v in enumerate(obj):
obj[i] = filter_data(v)
elif type(obj) == dict:
for i,v in obj.iteritems():
obj[i] = filter_data(v)
else:
print "invalid object in data, converting to string"
obj = str(obj)
return obj
просто используйте рассол вместо json для дампа и загрузки, например:
import json
import pickle
d = { 'field1': 'value1', 'field2': 2, }
json.dump(d,open("testjson.txt","w"))
print json.load(open("testjson.txt","r"))
pickle.dump(d,open("testpickle.txt","w"))
print pickle.load(open("testpickle.txt","r"))
вывод, который он производит (строки и целые числа обрабатываются правильно):
{u'field2': 2, u'field1': u'value1'}
{'field2': 2, 'field1': 'value1'}
поддержка Python2 & 3 с помощью крючка (отhttps://stackoverflow.com/a/33571117/558397)
import requests
import six
from six import iteritems
requests.packages.urllib3.disable_warnings() # @UndefinedVariable
r = requests.get("http://echo.jsontest.com/key/value/one/two/three", verify=False)
def _byteify(data):
# if this is a unicode string, return its string representation
if isinstance(data, six.string_types):
return str(data.encode('utf-8').decode())
# if this is a list of values, return list of byteified values
if isinstance(data, list):
return [ _byteify(item) for item in data ]
# if this is a dictionary, return dictionary of byteified keys and values
# but only if we haven't already byteified it
if isinstance(data, dict):
return {
_byteify(key): _byteify(value) for key, value in iteritems(data)
}
# if it's anything else, return it in its original form
return data
w = r.json(object_hook=_byteify)
print(w)
возвращает:
{'three': '', 'key': 'value', 'one': 'two'}
это поздно для игры, но я построил этот рекурсивный заклинатель. Он работает для моих нужд, и я думаю, что он относительно полный. Это может вам помочь.
def _parseJSON(self, obj):
newobj = {}
for key, value in obj.iteritems():
key = str(key)
if isinstance(value, dict):
newobj[key] = self._parseJSON(value)
elif isinstance(value, list):
if key not in newobj:
newobj[key] = []
for i in value:
newobj[key].append(self._parseJSON(i))
elif isinstance(value, unicode):
val = str(value)
if val.isdigit():
val = int(val)
else:
try:
val = float(val)
except ValueError:
val = str(val)
newobj[key] = val
return newobj
просто передайте ему объект JSON следующим образом:
obj = json.loads(content, parse_float=float, parse_int=int)
obj = _parseJSON(obj)
у меня есть это как частный член класса, но вы можете перепрофилировать метод, как считаете нужным.
я переписал Wells _parse_json () для обработки случаев, когда сам объект json является массивом (мой вариант использования).
def _parseJSON(self, obj):
if isinstance(obj, dict):
newobj = {}
for key, value in obj.iteritems():
key = str(key)
newobj[key] = self._parseJSON(value)
elif isinstance(obj, list):
newobj = []
for value in obj:
newobj.append(self._parseJSON(value))
elif isinstance(obj, unicode):
newobj = str(obj)
else:
newobj = obj
return newobj
вот рекурсивный кодировщик, написанный на C: https://github.com/axiros/nested_encode
накладные расходы на производительность для" средних " структур около 10% по сравнению с json.нагрузки.
python speed.py
json loads [0.16sec]: {u'a': [{u'b': [[1, 2, [u'\xd6ster..
json loads + encoding [0.18sec]: {'a': [{'b': [[1, 2, ['\xc3\x96ster.
time overhead in percent: 9%
С помощью этого teststructure осуществляет:
import json, nested_encode, time
s = """
{
"firstName": "Jos\u0301",
"lastName": "Smith",
"isAlive": true,
"age": 25,
"address": {
"streetAddress": "21 2nd Street",
"city": "\u00d6sterreich",
"state": "NY",
"postalCode": "10021-3100"
},
"phoneNumbers": [
{
"type": "home",
"number": "212 555-1234"
},
{
"type": "office",
"number": "646 555-4567"
}
],
"children": [],
"spouse": null,
"a": [{"b": [[1, 2, ["\u00d6sterreich"]]]}]
}
"""
t1 = time.time()
for i in xrange(10000):
u = json.loads(s)
dt_json = time.time() - t1
t1 = time.time()
for i in xrange(10000):
b = nested_encode.encode_nested(json.loads(s))
dt_json_enc = time.time() - t1
print "json loads [%.2fsec]: %s..." % (dt_json, str(u)[:20])
print "json loads + encoding [%.2fsec]: %s..." % (dt_json_enc, str(b)[:20])
print "time overhead in percent: %i%%" % (100 * (dt_json_enc - dt_json)/dt_json)
у меня был JSON dict как строка. Ключи и значения были объектами unicode, как в следующем примере:
myStringDict = "{u'key':u'value'}"
Я мог бы использовать
проверить этой ответ на подобный вопрос, как это, который гласит, что
U-префикс просто означает, что у вас есть строка Unicode. Когда вы действительно используете строку, она не будет отображаться в ваших данных. Не будьте брошены печатным выходом.
например, попробуйте это:
print mail_accounts[0]["i"]
вы не увидите u.
С Python 3.6, иногда я все еще сталкиваюсь с этой проблемой. Например, при получении ответа от REST API и загрузке текста ответа в JSON я все равно получаю строки unicode. Найдено простое решение с использованием json.отвал.)(
response_message = json.loads(json.dumps(response.text))
print(response_message)
Я тоже столкнулся с этой проблемой, и, имея дело с JSON, я придумал небольшой цикл, который преобразует ключи unicode в строки. (simplejson
on GAE не возвращает строковые ключи.)
obj
объект декодирован из JSON:
if NAME_CLASS_MAP.has_key(cls):
kwargs = {}
for i in obj.keys():
kwargs[str(i)] = obj[i]
o = NAME_CLASS_MAP[cls](**kwargs)
o.save()
kwargs
это то, что я передаю конструктору приложения GAE (которому не нравится unicode
ключи **kwargs
)
не такой надежный, как решение из скважин, но гораздо меньше.
я адаптировал код из ответ of Марк Амеры, в частности, для того, чтобы избавиться от isinstance
для профессионалов duck-typing.
кодировка выполняется вручную и ensure_ascii
отключено. Документы python для json.dump
говорит, что
если ensure_ascii имеет значение True (по умолчанию), все символы, отличные от ASCII, экранируются последовательностями \uXXXX
отказ от ответственности: в doctest я использовал венгерский язык. Некоторые известные венгерские кодировки символов:cp852
кодировка IBM / OEM используется, например. в DOS (иногда называют ascii, неправильно я думаю, это зависит от кодовая страница настройки), cp1250
используется например. в Windows (иногда называют в ANSI в зависимости от настройки локали), и iso-8859-2
, иногда используется на серверы http. Тестовый текст Tüskéshátú kígyóbűvölő
относится к Koltai Ласло (родная форма личного имени) и от Википедия.
# coding: utf-8
"""
This file should be encoded correctly with utf-8.
"""
import json
def encode_items(input, encoding='utf-8'):
u"""original from: https://stackoverflow.com/a/13101776/611007
adapted by SO/u/611007 (20150623)
>>>
>>> ## run this with `python -m doctest <this file>.py` from command line
>>>
>>> txt = u"Tüskéshátú kígyóbűvölő"
>>> txt2 = u"T\u00fcsk\u00e9sh\u00e1t\u00fa k\u00edgy\u00f3b\u0171v\u00f6l\u0151"
>>> txt3 = u"uúuutifu"
>>> txt4 = b'u\xfauutifu'
>>> # txt4 shouldn't be 'u\xc3\xbauutifu', string content needs double backslash for doctest:
>>> assert u'\u0102' not in b'u\xfauutifu'.decode('cp1250')
>>> txt4u = txt4.decode('cp1250')
>>> assert txt4u == u'u\xfauutifu', repr(txt4u)
>>> txt5 = b"u\xc3\xbauutifu"
>>> txt5u = txt5.decode('utf-8')
>>> txt6 = u"u\u251c\u2551uutifu"
>>> there_and_back_again = lambda t: encode_items(t, encoding='utf-8').decode('utf-8')
>>> assert txt == there_and_back_again(txt)
>>> assert txt == there_and_back_again(txt2)
>>> assert txt3 == there_and_back_again(txt3)
>>> assert txt3.encode('cp852') == there_and_back_again(txt4u).encode('cp852')
>>> assert txt3 == txt4u,(txt3,txt4u)
>>> assert txt3 == there_and_back_again(txt5)
>>> assert txt3 == there_and_back_again(txt5u)
>>> assert txt3 == there_and_back_again(txt4u)
>>> assert txt3.encode('cp1250') == encode_items(txt4, encoding='utf-8')
>>> assert txt3.encode('utf-8') == encode_items(txt5, encoding='utf-8')
>>> assert txt2.encode('utf-8') == encode_items(txt, encoding='utf-8')
>>> assert {'a':txt2.encode('utf-8')} == encode_items({'a':txt}, encoding='utf-8')
>>> assert [txt2.encode('utf-8')] == encode_items([txt], encoding='utf-8')
>>> assert [[txt2.encode('utf-8')]] == encode_items([[txt]], encoding='utf-8')
>>> assert [{'a':txt2.encode('utf-8')}] == encode_items([{'a':txt}], encoding='utf-8')
>>> assert {'b':{'a':txt2.encode('utf-8')}} == encode_items({'b':{'a':txt}}, encoding='utf-8')
"""
try:
input.iteritems
return {encode_items(k): encode_items(v) for (k,v) in input.iteritems()}
except AttributeError:
if isinstance(input, unicode):
return input.encode(encoding)
elif isinstance(input, str):
return input
try:
iter(input)
return [encode_items(e) for e in input]
except TypeError:
return input
def alt_dumps(obj, **kwargs):
"""
>>> alt_dumps({'a': u"T\u00fcsk\u00e9sh\u00e1t\u00fa k\u00edgy\u00f3b\u0171v\u00f6l\u0151"})
'{"a": "T\xc3\xbcsk\xc3\xa9sh\xc3\xa1t\xc3\xba k\xc3\xadgy\xc3\xb3b\xc5\xb1v\xc3\xb6l\xc5\x91"}'
"""
if 'ensure_ascii' in kwargs:
del kwargs['ensure_ascii']
return json.dumps(encode_items(obj), ensure_ascii=False, **kwargs)
я также хотел бы выделить ответ of Джаррет Харди, который ссылается на JSON spec, цитирую:
строка-это набор из нуля или более символов Unicode
в моем случае использования у меня были файлы с json. Они utf-8
зашифрованные файлы. ensure_ascii
результаты правильно экранированы, но не очень читабельны файлы json, вот почему я адаптировал ответ Марка Эмери в соответствии с моими потребностями.
doctest не особенно вдумчив, но я разделяю код в надежде, что он будет полезен для кого-то.