Python - декодированная строка Unicode не остается декодированной - PullRequest
0 голосов
/ 11 января 2019

Возможно, мне уже слишком поздно заниматься программированием (поэтому извиняюсь, если это очень глупая вещь), но я заметил странное поведение с декодированием строк в Python:

>>> bs = bytearray(b'I\x00n\x00t\x00e\x00l\x00(\x00R\x00)\x00')
>>> name = bs.decode("utf-8", "replace")
>>> print(name)
I n t e l ( R )
>>> list_of_dict = []
>>> list_of_dict.append({'name': name})
>>> list_of_dict
[{'name': 'I\x00n\x00t\x00e\x00l\x00(\x00R\x00)\x00'}] 

Как список может содержать символы Юникода, если он уже был декодирован?

Ответы [ 2 ]

0 голосов
/ 11 января 2019

Итак, я думаю, что символы с нулевым символом в конце \x00 неправильно декодируются и остаются в строке после декодирования. Однако, поскольку это нулевые символы, они не портятся, когда вы печатаете строку, которая интерпретирует их как ничего или пробелы (в моем случае я протестировал ваш код на arch linux на python2 и python3, и они были полностью опущены)

Теперь дело в том, что вы получили символ \x00 для каждого из ваших строковых символов, когда вы декодируете с помощью utf-8, так что это означает, что ваш байтпоток на самом деле состоит из 16-битных символов, а не 8-битных. Поэтому, если вы попытаетесь декодировать, используя utf-16, ваш код будет работать как шарм:)

>>> bs = bytearray(b'I\x00n\x00t\x00e\x00l\x00(\x00R\x00)\x00')
>>> t = bs.decode("utf-16", "replace")
>>> print(t)
Intel(R)
>>> t
'Intel(R)'
0 голосов
/ 11 января 2019

Декодирование байтов по определению создает «Юникод» (на самом деле текст, где Юникод - это то, как вы можете хранить произвольный текст, поэтому Python использует его внутренне для всего текста), поэтому, когда вы говорите «Как список может содержать символы Юникода, если он имеет уже был расшифрован? это выдает фундаментальное недопонимание того, что такое Юникод. Если у вас есть str в Python 3, это текст, и этот текст состоит из серии кодовых точек Unicode (с неопределенной внутренней кодировкой; фактически современные Python хранят в ASCII, latin-1, UCS-2 или UCS -4, в зависимости от наивысшего порядкового значения, а также иногда от кэширования представления UTF-8 или собственного представления wchar для использования с устаревшими модулями расширения).

Вы видите repr символа nul (порядковый номер Unicode 0) и думаете, что он не декодируется должным образом, и вы, вероятно, правы (нет ничего противозаконного в символах nul, они просто не распространены в простой текст); Ваши входные данные почти наверняка закодированы в UTF-16-LE, а не в UTF-8. Используйте правильный кодек, и текст выходит правильно:

>>> bs = bytearray(b'I\x00n\x00t\x00e\x00l\x00(\x00R\x00)\x00')
>>> bs.decode('utf-16-le')  # No need to replace things, this is legit UTF-16-LE
'Intel(R)'
>>> list_of_dict = [{'name': _}]
>>> list_of_dict
[{'name': 'Intel(R)'}]

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

Расхождение между печатью str и отображением является частью list / dict из-за того, что list / dict совпадает с repr их содержимого (то, что вы наберете во многих случаях программно воспроизводить объект), поэтому строка выводится с экранированием \x00. print непосредственное использование str не включает repr, поэтому символы nul отображаются в виде пробелов (поскольку для nul нет печатаемых символов, поэтому ваш терминал решил отобразить его как пробелы).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...