Jak uzyskać obiekty string zamiast Unicode z JSON?
Używam Pythona 2 do parsowania JSON z zakodowanych w ASCII plików tekstowych.
Podczas wczytywania tych plików z json
lub simplejson
, wszystkie moje wartości łańcuchowe są wysyłane do obiektów Unicode zamiast do obiektów łańcuchowych. Problem w tym, że muszę używać danych z niektórymi bibliotekami, które akceptują tylko obiekty string. Nie mogę zmienić bibliotek ani ich zaktualizować.
Czy możliwe jest uzyskanie obiektów string zamiast Unicode jeden?
Przykład
>>> 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`
Update
To pytanie zostało zadane dawno temu, kiedy utknąłem z Pythonem 2. Jednym z łatwych i czystych rozwiązań na dziś jest użycie najnowszej wersji Pythona - tj. Python 3 i forward.
21 answers
Rozwiązanie z 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
Przykładowe użycie:
>>> 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'}
Jak to działa i dlaczego miałbym go używać?
Funkcja Marka Amery ' ego jest krótsza i jaśniejsza od tych, więc jaki jest ich sens? Dlaczego chcesz ich użyć?
Wyłącznie dla wykonania. Mark ' s answer dekoduje tekst JSON w pełni najpierw za pomocą ciągów unicode, a następnie rekursuje całą dekodowaną wartość, aby przekonwertować wszystkie ciągi na ciągi bajtów. To ma kilka działań niepożądanych:
- Kopia całej zdekodowanej struktury zostaje utworzona w pamięci
- Jeśli twój obiekt JSON jest naprawdę głęboko zagnieżdżony (500 poziomów lub więcej), to osiągniesz maksymalną głębokość rekursji Pythona
Ta odpowiedź łagodzi oba te problemy z wydajnością, używając parametru object_hook
z json.load
i json.loads
. Z docs :
object_hook
jest funkcją opcjonalną, która zostanie wywołana z wynikiem dowolnego obiekt dosłowny dekodowany (adict
). Zwracana wartość object_hook zostanie użyta zamiastdict
. Ta funkcja może być używana do implementacji niestandardowych dekoderów
Ponieważ słowniki zagnieżdżone wiele poziomów głęboko w innych słownikach przechodzą do object_hook
ponieważ są one dekodowane , możemy bajteifikować dowolne łańcuchy lub listy wewnątrz nich w tym momencie i uniknąć potrzeby późniejszej głębokiej rekurencji.
Odpowiedź marka nie nadaje się do użycia jako object_hook
w obecnej postaci, ponieważ rekursuje do zagnieżdżonych słowników. Zapobiegamy tej rekurencji w tej odpowiedzi za pomocą parametru ignore_dicts
na _byteify
, który jest przekazywany do niego przez cały czas Z wyjątkiem, gdy object_hook
przekazuje mu nowe dict
do byteify. Znacznik ignore_dicts
mówi _byteify
, aby ignorować dict
s, ponieważ zostały one już bajtowane.
Wreszcie, nasze implementacje json_load_byteified
i json_loads_byteified
wywołują _byteify
(z ignore_dicts=True
) NA wyniku zwróconym z json.load
lub json.loads
, aby obsłużyć przypadek, w którym dekodowany tekst JSON nie ma dict
w najwyższy poziom.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:47:14
Chociaż jest kilka dobrych odpowiedzi tutaj, skończyło się na użyciuPyYAML do analizy moich plików JSON, ponieważ daje klucze i wartości jako str
type strings zamiast unicode
type. Ponieważ JSON jest podzbiorem YAML to działa ładnie:
>>> 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']
Uwagi
Kilka rzeczy do zauważenia:
Otrzymuję obiekty string ponieważ wszystkie moje wpisy są zakodowane ASCII . Jeśli użyłbym wpisów zakodowanych w unicode, otrzymałbym je z powrotem jako unicode obiekty - Nie ma konwersji!
Powinieneś (prawdopodobnie zawsze) używać funkcji
safe_load
Pyyamla; jeśli używasz jej do ładowania plików JSON, nie potrzebujesz "dodatkowej mocy" funkcjiload
.Jeśli chcesz parser YAML, który ma więcej wsparcia dla wersji 1.2 spec (i poprawnie parsuje bardzo niskie liczby ) spróbuj Ruamel YAML:
pip install ruamel.yaml
andimport ruamel.yaml as yaml
was all I needed in my testy.
Konwersja
Jak stwierdzono, nie ma nawrócenia! Jeśli nie możesz być pewien, że zajmujesz się tylko wartościami ASCII (i nie możesz być pewien przez większość czasu), lepiej Użyj funkcji konwersji:
Używałem tej z Mark Amery teraz kilka razy, działa świetnie i jest bardzo łatwy w użyciu. Możesz również użyć podobnej funkcji jako object_hook
, ponieważ może to zwiększyć wydajność dużych plików. Zobacz też: odpowiedź od Mirec Miskuf za to.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:53
Nie ma wbudowanej opcji, aby Funkcje modułu json zwracały ciągi bajtów zamiast ciągów unicode. Jednak ta krótka i prosta funkcja rekurencyjna przekonwertuje dowolny zdekodowany obiekt JSON z ciągów unicode na kodowane UTF-8 ciągi bajtów:
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
Po prostu wywołaj to na wyjściu otrzymanym z json.load
lub json.loads
.
Kilka uwag:
- Aby Obsługiwać Python 2.6 lub wcześniejszy, zamień
return {byteify(key): byteify(value) for key, value in input.iteritems()}
nareturn dict([(byteify(key), byteify(value)) for key, value in input.iteritems()])
, ponieważ składanie słownika nie było obsługiwane do Pythona 2.7. - ponieważ ta odpowiedź przenika przez cały zdekodowany obiekt, ma ona kilka niepożądanych cech wydajności, których można uniknąć przy bardzo ostrożnym użyciu parametrów
object_hook
lubobject_pairs_hook
. odpowiedź Mireca Miskufa jest jak na razie jedyną, która potrafi to zrobić poprawnie, chociaż w konsekwencji jest to znacznie bardziej skomplikowane niż moje podejście.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:26
Możesz użyć parametru object_hook
dla json.loads
aby przejść w konwerterze. Nie musisz robić nawrócenia po fakcie. Na json
Moduł zawsze przekaże tylko dicty object_hook
i będzie przechodził rekurencyjnie w zagnieżdżonych dictach, więc nie musisz sam rekurencyjnie przechodzić do zagnieżdżonych dictów. Nie sądzę, bym konwertował ciągi unicode na liczby jak Wells shows. Jeśli jest to ciąg znaków unicode, został zacytowany jako ciąg znaków w pliku JSON, więc powinien to być ciąg znaków (lub plik jest zły).
Również starałbym się unikać robienia czegoś takiego jak str(val)
na unicode
obiekcie. Powinieneś używać value.encode(encoding)
z poprawnym kodowaniem, w zależności od tego, czego oczekuje twój zewnętrzny lib.
Więc, na przykład:
def _decode_list(data):
rv = []
for item in data:
if isinstance(item, unicode):
item = item.encode('utf-8')
elif isinstance(item, list):
item = _decode_list(item)
elif isinstance(item, dict):
item = _decode_dict(item)
rv.append(item)
return rv
def _decode_dict(data):
rv = {}
for key, value in data.iteritems():
if isinstance(key, unicode):
key = key.encode('utf-8')
if isinstance(value, unicode):
value = value.encode('utf-8')
elif isinstance(value, list):
value = _decode_list(value)
elif isinstance(value, dict):
value = _decode_dict(value)
rv[key] = value
return rv
obj = json.loads(s, object_hook=_decode_dict)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-29 17:33:12
Dzieje się tak dlatego, że json nie ma różnicy między obiektami string i Unicode. Wszystkie są ciągami w javascript.
Myślę, że JSON ma rację zwracając obiekty unicode . W rzeczywistości nie akceptowałbym niczego mniej, ponieważ łańcuchy javascript są w rzeczywistości unicode
obiektami (np. łańcuchy JSON (javascript) mogą przechowywać dowolny rodzaj znaku unicode), więc sensowne jest tworzenie unicode
obiektów przy tłumaczeniu łańcuchów z JSON. Zwykłe struny po prostu nie pasują od biblioteka musiałaby odgadnąć kodowanie, które chcesz.
Lepiej używać unicode
obiektów string wszędzie. Więc najlepszą opcją jest aktualizacja bibliotek, aby mogły radzić sobie z obiektami unicode.
Ale jeśli naprawdę chcesz bajtstrings, po prostu Zakoduj wyniki do wybranego kodowania:
>>> nl = json.loads(js)
>>> nl
[u'a', u'b']
>>> nl = [s.encode('utf-8') for s in nl]
>>> nl
['a', 'b']
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-05 18:29:06
Istnieje łatwe obejście.
TL; DR-Użyj ast.literal_eval()
zamiast json.loads()
. Zarówno ast
, jak i json
znajdują się w bibliotece standardowej.
Chociaż nie jest to odpowiedź "idealna", to jest dość daleko, jeśli planujesz całkowicie zignorować Unicode. W Pythonie 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))
Daje:
JSON Fail: {u'field': u'value'}
AST Win: {'field': 'value'}
Robi się to bardziej owłosione, gdy niektóre obiekty są ciągami Unicode. Pełna odpowiedź robi się Owłosiona szybko.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-11-07 01:01:43
Obawiam się, że nie ma możliwości osiągnięcia tego automatycznie w bibliotece simplejson.
Skaner i dekoder w simplejson są zaprojektowane do tworzenia tekstu unicode. Aby to zrobić, biblioteka używa funkcji o nazwie c_scanstring
(jeśli jest dostępna, dla szybkości) lub py_scanstring
, Jeśli wersja C nie jest dostępna. Funkcja scanstring
jest wywoływana kilka razy przez prawie każdą procedurę, którą simplejson ma do dekodowania struktury, która może zawierać tekst. Musisz albo monkeypatch wartość scanstring
w simplejson.dekoder lub podklasa JSONDecoder
i zapewnij prawie całą własną implementację wszystkiego, co może zawierać tekst.
Powodem, dla którego simplejson wysyła unicode, jest to, że JSON spec wyraźnie wspomina, że "łańcuch jest zbiorem zero lub więcej znaków Unicode"... obsługa unicode jest przyjmowana jako część samego formatu. Implementacja scanstring
simplejsona sięga tak daleko, że skanuje i interpretuje ucieczki unicode (nawet sprawdzanie błędów dla zniekształcone wielobajtowe reprezentacje znaków), więc jedynym sposobem na niezawodne zwrócenie ci wartości jest unicode.
Jeśli masz starszą bibliotekę, która wymaga str
, polecam albo mozolne przeszukiwanie zagnieżdżonej struktury danych po przetworzeniu (co przyznaję jest tym, czego wyraźnie powiedziałeś, że chcesz uniknąć... sorry), a może owinąć biblioteki w jakąś fasadę, gdzie można masować parametry wejściowe na bardziej ziarnistym poziomie. Drugie podejście może być bardziej zarządzalne niż pierwsze, jeśli struktury danych są rzeczywiście głęboko zagnieżdżone.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-06-05 18:10:03
Odpowiedź Mike ' a Brennana jest bliska, ale nie ma powodu, by przechodzić przez całą strukturę. Jeśli używasz object_hook_pairs
(Python 2.7+) parametr:
Dzięki niemu otrzymujesz każdy obiekt JSON, więc możesz dekodować bez potrzeby rekurencji:]}
object_pairs_hook
jest opcjonalną funkcją, która zostanie wywołana z wynikiem dowolnego obiektu literalnie zdekodowanego z uporządkowaną listą par. Wartość zwracanaobject_pairs_hook
zostanie użyty zamiastdict
. Ta funkcja może być wykorzystana do wdrożenia niestandardowych dekoderów, które opierają się na kolejności, że klucz i pary wartości są dekodowane(na przykładcollections.OrderedDict
zapamięta kolejność wstawiania). Jeśliobject_hook
określa się również, żeobject_pairs_hook
ma pierwszeństwo.
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'}}
Zauważ, że nigdy nie muszę wywoływać Hooka rekurencyjnie, ponieważ każdy obiekt zostanie przekazany hookowi, gdy użyjesz object_pairs_hook
. Trzeba troszczyć się o listy, ale jak widać, obiekt wewnątrz lista zostanie poprawnie przekonwertowana i nie musisz rekurencyjnie jej wykonywać.
EDIT: współpracownik zauważył, że Python2.6 nie ma object_hook_pairs
. Nadal możesz użyć tego will Python2. 6, dokonując bardzo małej zmiany. W haku powyżej, zmiana:
for key, value in pairs:
Do
for key, value in pairs.iteritems():
Następnie użyj object_hook
zamiast 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'}}
Użycie object_pairs_hook
powoduje utworzenie jednego słownika mniej dla każdego obiektu w obiekcie JSON, co, jeśli analizujesz ogromny dokument, może warto.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:33
Jak poprawnie zauważa Mark (Amery): użycie deserializera PyYaml na zrzut json działa tylko wtedy, gdy masz tylko ASCII. Przynajmniej po wyjęciu z pudełka.
Dwa szybkie komentarze na temat podejścia PyYaml:
-
You can make it work also for non ASCII via this:
def to_utf8(loader, node): return loader.construct_scalar(node).encode('utf-8') yaml.add_constructor(u'tag:yaml.org,2002:str', to_utf8)
Ale wydajność nie ma porównania do odpowiedzi Marka Amery ' ego:
Rzucając kilka głęboko zagnieżdżonych dictów próbek na dwie metody, rozumiem to (z DT [j] = delta czasu JSON.Łady(json."dumps (m)"): {]}
dt[yaml.safe_load(json.dumps(m))] =~ 100 * dt[j]
dt[byteify recursion(Mark Amery)] =~ 5 * dt[j]
Więc deserializacja obejmująca pełne poruszanie się po drzewie i kodowanie , dokładnie w granicach rzędu wielkości implementacji opartej na json C. Uważam, że jest to niezwykle szybkie, a także bardziej wytrzymałe niż obciążenie yaml przy głęboko zagnieżdżonych strukturach. I mniej podatne na błędy bezpieczeństwa, patrząc na yaml.ładuj.
=> chociaż byłbym wdzięczny za wskaźnik do konwertera opartego tylko na C, to funkcja byteify powinna być domyślną odpowiedzią.
Jest to szczególnie ważne, jeśli twoja struktura json pochodzi z pola zawierającego dane wejściowe użytkownika. Ponieważ wtedy prawdopodobnie będziesz musiał przejść po swojej strukturze-niezależnie od pożądanych wewnętrznych struktur danych(tylko 'Unicode sandwich' lub ciągi bajtów).
Dlaczego?Unicode normalizacja . Na weź środek przeciwbólowy i przeczytaj to .
Więc używając rekurencji byteify zabijasz dwie pieczenie jednym kamieniem:
- pobieraj bajty z zagnieżdżonych zrzutów json
- znormalizuj wartości wejściowe użytkownika, aby znaleźć rzeczy w magazynie.
W moich testach okazało się, że wymiana wejścia.kodowanie ('utf-8') za pomocą unicodedata.normalize ('NFC', input).kodowanie ('utf-8') było jeszcze szybsze niż w/O NFC - ale to w dużym stopniu zależy od próbki chyba data.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-14 17:42:03
The gotcha is that simplejson
and json
are two different modules, at least in the way they deal with unicode. MASZ json
w py 2.6+, co daje Ci wartości unicode, podczas gdy simplejson
zwraca obiekty string. Po prostu spróbuj easy_install-ING simplejson w swoim środowisku i sprawdź, czy to działa. Dla mnie tak.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-19 19:48:34
Więc napotkałem ten sam problem. Zgadnij, jaki był pierwszy wynik Google.
Ponieważ muszę przekazać wszystkie dane do PyGTK, łańcuchy unicode też nie są dla mnie zbyt przydatne. Mam więc inną rekurencyjną metodę konwersji. Jest również potrzebny do konwersji typu JSON - json.dump() zwalnia wszystkie Nie-literały, takie jak obiekty Pythona. Nie konwertuje jednak indeksów 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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-07-05 18:22:51
Po prostu użyj pickle zamiast json do zrzutu i załadowania, w ten sposób:
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"))
Generowane przez niego wyjście to (ciągi i liczby całkowite są obsługiwane poprawnie):
{u'field2': 2, u'field1': u'value1'}
{'field2': 2, 'field1': 'value1'}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-27 20:15:01
Obsługa Python2 i 3 za pomocą Hooka (z 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)
Zwraca:
{'three': '', 'key': 'value', 'one': 'two'}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-21 20:16:47
Jest późno na grę, ale zbudowałem ten rekurencyjny caster. Działa na moje potrzeby i myślę, że jest stosunkowo kompletny. To może Ci pomóc.
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
Po prostu podaj obiekt JSON w ten sposób:
obj = json.loads(content, parse_float=float, parse_int=int)
obj = _parseJSON(obj)
Mam to jako prywatny członek klasy, ale możesz zmienić sposób, jak uważasz za stosowne.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-29 03:53:43
Przepisałem _parse_json () Wellsa do obsługi przypadków, w których sam obiekt json jest tablicą (mój przypadek użycia).
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-07 05:12:22
Oto koder rekurencyjny napisany w C: https://github.com/axiros/nested_encode
Wydajność dla "średnich" struktur około 10% w porównaniu do json.mnóstwo.
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%
Za pomocą tego testu:
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)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-05-04 12:44:46
Miałem JSON dict jako ciąg. Klucze i wartości były obiektami unicode, jak w poniższym przykładzie:
myStringDict = "{u'key':u'value'}"
Mógłbym użyć funkcji byteify
zaproponowanej powyżej, konwertując łańcuch znaków na obiekt dict
za pomocą ast.literal_eval(myStringDict)
.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-11-17 15:17:21
Sprawdź to odpowiedź na podobne pytanie, które stwierdza, że
Przedrostek u oznacza tylko, że masz ciąg Unicode. Gdy naprawdę użyjesz tego ciągu, nie pojawi się on w Twoich danych. Nie daj się wyrzucić przez wydrukowane wyjście.
Na przykład, spróbuj tego:
print mail_accounts[0]["i"]
Nie zobaczysz u.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-04 13:32:45
W Pythonie 3.6, czasami wciąż napotykam ten problem. Na przykład, gdy otrzymuję odpowiedź z REST API i ładuję tekst odpowiedzi do JSON, nadal otrzymuję ciągi znaków unicode. Znalazłem proste rozwiązanie przy użyciu json.zrzuty ().
response_message = json.loads(json.dumps(response.text))
print(response_message)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-04-25 17:17:55
Też napotkałem ten problem i mając do czynienia z JSONEM, wpadłem na małą pętlę, która konwertuje klucze unicode na ciągi. (simplejson
na GAE nie zwraca kluczy łańcuchowych.)
obj
jest obiektem zdekodowanym z 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
jest to, co przekazuję konstruktorowi aplikacji GAE (która nie lubi unicode
kluczy w **kwargs
)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-29 17:01:18
Zaadaptowałem kod z odpowiedzi z Marka Amery'ego , szczególnie po to, aby pozbyć się isinstance
dla profesjonalistów z Duck-typingu.
Kodowanie jest wykonywane ręcznie i ensure_ascii
jest wyłączone. Python docs for json.dump
mówi, że
Jeśli ensure_ascii jest prawdziwe( domyślne), wszystkie znaki spoza ASCII na wyjściu są przetwarzane za pomocą sekwencji \uXXXX
Zastrzeżenie: w doctest użyłem języka węgierskiego. Niektóre godne uwagi Kodowanie znaków związane z językiem węgierskim to: cp852
kodowanie IBM/OEM używane np. w DOS (czasami określane jako ascii , błędnie myślę, że zależy to od ustawienia codepage ), cp1250
używane np. w Windows (czasami określane jako ansi, zależne od ustawień regionalnych) i iso-8859-2
, czasami używane na serwerach http. Tekst testowy Tüskéshátú kígyóbűvölő
przypisany jest Koltai László (rodzima forma imienia) i pochodzi z Wikipedii.
# 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)
I ' d chciałbym również podkreślić odpowiedź z Jarret Hardie , która odwołuje się do JSON spec , cytując:
Łańcuch jest zbiorem zero lub więcej znaków Unicode
W moim przypadku użycia miałem pliki z json. Są to utf-8
zakodowane pliki. ensure_ascii
powoduje poprawne ucieczki, ale niezbyt czytelne pliki json, dlatego dostosowałem odpowiedź Marka Amery ' ego do moich potrzeb.
Doctest nie jest specjalnie przemyślany, ale podzielam kod w nadziei, że będzie przydatny dla kogoś.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-03 07:59:46