Почему json.dumps сбрасывает символы не-ascii с помощью "\ uxxxx"

В Python 2 функция json.dumps() гарантирует, что все символы без ascii будут экранированы как \uxxxx .

Python 2 Json

Но разве это не сбивает с толку, потому что \uxxxx является символом юникода и должен использоваться внутри строки юникода.

Вывод json.dumps() – это str , которая является байтовой строкой в ​​Python 2. И, таким образом, не следует избегать символов как \xhh ?

 >>> unicode_string = u"\u00f8" >>> print unicode_string ø >>> print json.dumps(unicode_string) "\u00f8" >>> unicode_string.encode("utf8") '\xc3\xb8' 

3 Solutions collect form web for “Почему json.dumps сбрасывает символы не-ascii с помощью "\ uxxxx"”

Это точно. Вы возвращаете байтовую строку, а не строку Unicode. Таким образом, символы Юникода должны быть экранированы, чтобы выжить. Выделение разрешено JSON и, таким образом, представляет собой безопасный способ представления символов Unicode.

Почему json.dumps сбрасывает символы не-ascii с помощью "\ uxxxx"

Python 2 может смешивать только ascii-only bytestrings и строки Unicode.

Это может быть преждевременная оптимизация. Строки Unicode могут потребовать в 2-4 раза больше памяти, чем соответствующие байты, если они содержат символы в основном в ASCII-диапазоне в Python 2.

Кроме того, даже сегодня print(unicode_string) может легко завершиться неудачей, если она содержит символы, отличные от ascii, при печати на консоли Windows, если не установлено что-то вроде пакета Python для win-unicode-console . Он может потерпеть неудачу даже в Unix, если используется язык C / POSIX (по умолчанию для служб init.d , ssh , cron ) (это подразумевает кодировку символов ascii. Существует C.UTF-8 но она не всегда доступна, и вы необходимо настроить его явно). Это может объяснить, почему вы, возможно, захотите в некоторых случаях обеспечить ensure_ascii=True .

Формат JSON определен для текста Unicode, и, строго говоря, json.dumps() всегда должен возвращать строку Unicode, но может возвращать байтовую строку, если все символы находятся в диапазоне ASCII ( xml.etree.ElementTree имеет аналогичную «оптимизацию»). Сложно предположить, что Python 2 позволяет обрабатывать ascii-only bytestring как строку Unicode в некоторых случаях (допускаются неявные преобразования). Python 3 более строгий (неявные преобразования запрещены).

Вместо строк Unicode (с возможными символами, отличными от ASCII) могут использоваться только байты ASCII, чтобы сохранить память и / или улучшить взаимодействие в Python 2.

Чтобы отключить это поведение, используйте json.dumps(obj, ensure_ascii=False) .


Важно не путать строку Unicode с ее представлением в исходном коде Python как строковый литерал Python или его представление в файле как текст JSON.

Формат JSON позволяет избежать любого символа, а не только символов Unicode вне диапазона ASCII:

 >>> import json >>> json.loads(r'"\u0061"') u'a' >>> json.loads('"a"') u'a' 

Не путайте его с помощью экранов в строковых литералах Python, используемых в исходном коде Python. u"\u00f8" является единственным символом Unicode, но "\u00f8" в выводе составляет восемь символов (в исходном коде Python вы можете использовать его как r'"\u00f8"' == '"\\u00f8"' == u'"\\u00f8"' (обратная косая черта является особенной как в литералах Python, так и в json-тексте – может произойти двойное экранирование ). Также нет r'"\u00f8"' == '"\\u00f8"' == u'"\\u00f8"' в JSON:

 >>> json.loads(r'"\x61"') # invalid JSON Traceback (most recent call last): ... ValueError: Invalid \escape: line 1 column 2 (char 1) >>> r'"\x61"' # valid Python literal (6 characters) '"\\x61"' >>> '"\x61"' # valid Python literal with escape sequence (3 characters) '"a"' 

Вывод json.dumps () – это str, которая является байтовой строкой в ​​Python 2. И, таким образом, не следует избегать символов как \ xhh?

json.dumps(obj, ensure_ascii=True) создает только печатные символы ascii и поэтому print repr(json.dumps(u"\xf8")) не будет содержать \xhh , которые используются для представления ( repr() ) non- печатные символы (байты).

\u могут быть необходимы даже для входа ascii:

 #!/usr/bin/env python2 import json print json.dumps(map(unichr, range(128))) 

Вывод

 ["\u0000", "\u0001", "\u0002", "\u0003", "\u0004", "\u0005", "\u0006", "\u0007", "\b", "\t", "\n", "\u000b", "\f", "\r", "\u000e", "\u000f", "\u0010", "\u0011", "\u0012", "\u0013", "\u0014", "\u0015", "\u0016", "\u0017", "\u0018", "\u0019", "\u001a", "\u001b", "\u001c", "\u001d", "\u001e", "\u001f", " ", "!", "\"", "#", "$", "%", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", ":", ";", "<", "=", ">", "?", "@", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "[", "\\", "]", "^", "_", "`", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "{", "|", "}", "~", "\u007f"] 

Но разве это не сбивает с толку, потому что \ uxxxx является символом юникода и должен использоваться внутри строки юникода

\uxxxx – 6 символов, которые могут быть интерпретированы как один символ в некоторых контекстах, например, в исходном коде Python. u"\uxxxx" – это литерал Python, который создает строку Unicode в памяти с одним символом Unicode. Но если вы видите \uxxxx в json-тексте; это шесть символов, которые могут представлять один символ Unicode, если вы загрузите его ( json.loads() ).

На этом этапе вы должны понять, почему len(json.loads('"\\\\"')) == 1 .

\u в "\u00f8" самом деле не является escape-последовательностью, такой как \x . \u – буква r'\u' . Но такие строки байтов могут быть легко преобразованы в Unicode.

Демо-версия:

 s = "\u00f8" u = s.decode('unicode-escape') print repr(s), len(s), repr(u), len(u) s = "\u2122" u = s.decode('unicode-escape') print repr(s), len(s), repr(u), len(u) 

вывод

 '\\u00f8' 6 u'\xf8' 1 '\\u2122' 6 u'\u2122' 1 

Как упоминает JFSebastian в комментариях, внутри строки Unicode \u00f8 является истинным кодом escape, то есть в строке Python 3 или в строке Python 2 u"\u00f8" . Также обратите внимание на его другие замечания!

  • Python: Как заставить StringIO.writelines принимать строку Unicode?
  • Как сделать Python split () на языках (например, китайском), которые не используют пробелы в качестве разделителя слов?
  • Есть ли простой способ сделать работу юникода в python?
  • Удаление символов, отличных от ASCII, из строки с использованием python / django
  • Как узнать номер / имя символа юникода в Python?
  • CSV, Python: правильно использовать DictWriter (ValueError: dict содержит поля не в именах полей)
  • Коды символов юникода Python?
  • Преобразование unicode с помощью строки utf-8 в качестве содержимого для str
  • Python UTF-8 XML-синтаксический анализ (SUDS): удаление «недопустимого токена»
  • Нормализация текста Unicode для имен файлов и т. Д. В Python
  • Python Как исправить сломанную кодировку utf-8?
  •  
    Interesting Posts for Van-Lav

    Плохой дескриптор файла – Heroku Foreman

    Нужна помощь в создании рекурсивного синтаксического анализа, используя пираринг

    Объяснить синтаксис пифа Apache Beam

    redis.exceptions.ConnectionError: Ошибка -2 подключение к localhost: 6379. Имя или услуга неизвестны

    Как сделать поле не редактируемым в представлении Flask Admin для класса модели

    Объект Python в QMimeData

    Операции, основанные на времени, основанные на векселях, в которых имеет место состояние предшествующих элементов, – соответствуют ли петли?

    Строка графика Trendline не работает с bigdataset

    Извлечение элементов массива с массивом частот в NumPy

    Как вывести XML-контент с носетистами?

    Пример обработки изображений MCMC в Matlab или Python

    Python: Почему параметры функции int & list обрабатываются по-разному?

    JSON to pandas DataFrame

    Добавьте элемент между каждым элементом, уже находящимся в списке

    Проверьте, является ли параметр модулем Python?

    Python - лучший язык программирования в мире.