Почему 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, file (1) - Почему числа и диапазон (0x20, 0x100) используются для определения текстового или двоичного файла
  • Проблемы с Unicode при использовании io.StringIO для издевательства файла
  • Python string.format () и Unicode
  • Преобразовать символы ASCII в латинские буквы Unicode FULLWIDTH в Python?
  • Python 3 smtplib отправляет с символами unicode
  • Как эти строки представлены внутри интерпретатора Python? Я не понимаю
  • ElementTree и unicode
  • Python: UnicodeDecodeError: кодек ascii не может декодировать байт 0xef в позиции 0: порядковый номер не в диапазоне (128)
  •  
    Interesting Posts for Van-Lav

    Как установить ipton qtconsole с pyenv (Python версии 3.4.2)

    Как запустить скрипт Python, который является частью приложения, которое я загрузил в сеансе AWS SSH?

    дважды щелкните файл, чтобы запустить скрипт python. как получить этот файл в качестве входа?

    Сериализация модели django с внешними ключами

    Ошибка из памяти в opencv3.0, которая запускается внутри контейнера докеров

    Тройной оператор шаблонов шаблонов Django

    Итерация над матрицей с нулевым размером неизвестного размера

    Установка Python Tools для Visual Studio 2012 (PTVS)

    Как проверить, существует ли значение в словаре (python)

    Почему или скорее, как объект .__ new__ работает по-разному в этих двух случаях

    Xpath анализирует всю страницу, когда я указываю не

    Панды определяют начало, конец и дно рецессии на основе ВВП

    PySide: Segfault (?) При использовании QItemSelectionModel с QListView

    Python BeautifulSoup Получение столбца из таблицы – индекс индекса IndexError вне диапазона

    Как удалить все знаки препинания в строке? (Python)

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