У меня есть следующий текст в файле json:

"\u00d7\u0090\u00d7\u0097\u00d7\u0095\u00d7\u0096\u00d7\u00aa 
\u00d7\u00a4\u00d7\u0095\u00d7\u009c\u00d7\u0092"

Что представляет собой текст «אחוזת פולג» на иврите.

Независимо от того, какое кодирование / декодирование я использую, я, кажется, не понимаю с Python 3.

Если, например, я попробую:

text = "\u00d7\u0090\u00d7\u0097\u00d7\u0095\u00d7\u0096\u00d7\u00aa 
\u00d7\u00a4\u00d7\u0095\u00d7\u009c\u00d7\u0092".encode('unicode-escape')

print(text)

Я получаю этот текст:

b'\\xd7\\x90\\xd7\\x97\\xd7\\x95\\xd7\\x96\\xd7\\xaa \\xd7\\xa4\\xd7\\x95\\xd7\\x9c\\xd7\\x92'

Который в байт-коде является почти правильным текстом, если бы мне удалось удалить только одну обратную косую черту и повернуть

b'\\xd7\\x90\\xd7\\x97\\xd7\\x95\\xd7\\x96\\xd7\\xaa \\xd7\\xa4\\xd7\\x95\\xd7\\x9c\\xd7\\x92'

В

text = b'\xd7\x90\xd7\x97\xd7\x95\xd7\x96\xd7\xaa \xd7\xa4\xd7\x95\xd7\x9c\xd7\x92'

(обратите внимание, как я изменил двойную косую черту на одинарную), затем

text.decode('utf-8')

Даст правильный текст на иврите.

Но я изо всех сил пытаюсь это сделать, и мне не удалось создать фрагмент кода, который сделает это за меня (а не вручную, как я только что показал ...)

Любая помощь очень ценится ...

3
Limitless 22 Сен 2018 в 16:27

1 ответ

Лучший ответ

Эта строка не «представляет» текст на иврите (по крайней мере, не в виде кодовых точек Unicode, UTF-16, UTF-8 или каким-либо известным способом). Вместо этого он представляет собой последовательность кодовых единиц UTF-16, и эта последовательность состоит в основном из знаков умножения, знаков валюты и некоторых странных управляющих символов.

Похоже, что исходные символьные данные были закодированы и декодированы несколько раз с какой-то странной комбинацией кодировок.

Предполагая, что это то, что буквально сохраняется в вашем файле JSON:

"\u00d7\u0090\u00d7\u0097\u00d7\u0095\u00d7\u0096\u00d7\u00aa \u00d7\u00a4\u00d7\u0095\u00d7\u009c\u00d7\u0092"

Вы можете восстановить текст на иврите следующим образом:

(jsonInput
  .encode('latin-1')
  .decode('raw_unicode_escape')
  .encode('latin-1')
  .decode('utf-8')
)

В приведенном выше примере это дает:

'אחוזת פולג'

Если вы используете десериализатор JSON для чтения данных, вам, конечно, следует опустить шаги .encode('latin-1').decode('raw_unicode_escape'), потому что десериализатор JSON уже будет интерпретировать escape-последовательности за вас. То есть после загрузки текстового элемента десериализатором JSON должно быть достаточно просто закодировать его как latin-1, а затем декодировать как utf-8. Это работает, потому что latin-1 (ISO-8859-1) представляет собой 8-битную кодировку символов, которая точно соответствует первым 256 кодовым точкам Unicode, тогда как ваш странно сломанный текст кодирует каждый байт кодировки UTF-8 как ASCII -эскейп от кодовой единицы UTF-16.

Я не уверен, что вы можете сделать, если ваш JSON содержит одновременно неработающие escape-последовательности и действительный текст. Возможно, latin-1 больше не работает должным образом. Пожалуйста, не применяйте это преобразование к вашему файлу JSON, если сам JSON не содержит только ASCII, это только ухудшит ситуацию.

4
Andrey Tyukin 22 Сен 2018 в 21:48