Преобразование символов Юникода из возвращенного JSON в python

Я пытаюсь вернуть JSON из службы API от musicbrainz, возвращаемые данные для некоторых песен содержат символы юникода, из-за которых у меня возникают проблемы с преобразованием их в обычные символы и т. д. Пожалуйста, дайте мне знать, что мне следует делать здесь.

JSON:

{
    "status": "ok",
    "results": [{
        "recordings": [{
            "duration": 402,
            "tracks": [{
                "duration": 402,
                "position": 6,
                "medium": {
                    "release": {
                        "id": "dde6ecee-8e9b-4b46-8c28-0f8d659f83ac",
                        "title": "Tecno Fes, Volume 2"
                    },
                    "position": 1,
                    "track_count": 11
                },
                "artists": [{
                    "id": "57c1e5ea-e08f-413a-bcb1-f4e4b675bead",
                    "name": "Gigi D\u2019Agostino"
                }],
                "title": "You Spin Me Round"
            }],
            "id": "2e0a7bce-9e44-4a63-a789-e8c4d2a12af9"
        }, ....

Неудачный код (пример):

string = '\u0420\u043e\u0441\u0441\u0438\u044f'
print string.encode('utf-8')

Я использую это на машине с Windows 7 и имею Python 2.7 и запускаю этот код в терминале командной строки. У меня есть вывод, который я получаю ниже:

C:\Python27>python junk.py Gigi DGÇÖAgostino Gigi D?Agostino Gigi D\u2019Agostino

Я ожидаю, что результат будет Gigi D' Agostino


person Prem Minister    schedule 15.01.2013    source источник
comment
Что такое нормальный персонаж?   -  person tkone    schedule 15.01.2013
comment
Я не уверен, что именно ваш вопрос здесь. Я прогнал JSON, который вы дали, через стандартный декодер JSON, и один бит не-ASCII вышел правильно как Gigi D’Agostino. Неудачный код, вы просто пропустили символ. Если вы пишете string = u'\u0420\u043e\u0441\u0441\u0438\u044f', переменная правильно устанавливается в Россия. Кстати, не используйте строку в качестве имени переменной; это может закончиться только слезами.   -  person Malvolio    schedule 15.01.2013
comment
Вы имеете в виду, что вам нужны строки в кодировке ASCII? Почему? Что вы на самом деле делаете с этими данными?   -  person Silas Ray    schedule 15.01.2013
comment
Я пытаюсь получить некоторые метаданные, которые в конечном итоге будут использоваться для управления мультимедиа, поэтому необходимо правильно их кодировать. желаемый результат - Джиджи Д'Агостино, в то время как все испробованные коды и методы не решают эту проблему... ‹br› print u'Gigi D\u2019Agostino'.encode('utf-8')' ‹br› print u'Gigi D\u2019Agostino'.encode('iso-8859-15', 'replace') ‹br› a = u'Gigi D\u2019Agostino' import re a = re.sub(r'[\x80-\xFF]+', lambda x: x.group(0).encode('latin1').decode('utf8'), a) print a.encode('utf8')   -  person Prem Minister    schedule 15.01.2013
comment
вы не забыли указать кодировку в скрипте? # -*- encoding: utf-8 -*-   -  person der_fenix    schedule 15.01.2013
comment
Перепробовал все способы, описанные ниже, но ни один из них не помог... # -*- encoding: utf-8 -*- print u'Gigi D\u2019Agostino'.encode('utf-8') print u'Gigi D\u2019Agostino'.encode('iso-8859-15', 'replace') out = 'Gigi D\u2019Agostino' out = out.replace( u'\u2018', u"'") out = out.replace( u'\u2019', u"'") out = out.replace( u'\u201c', u'"') out = out.replace( u'\u201d', u'"') out.encode('ascii') print out a = u'Gigi D\u2019Agostino' import re a = re.sub(r'[\x80-\xFF]+', lambda x: x.group(0).encode('latin1').decode('utf8'), a) print a.encode('utf8')   -  person Prem Minister    schedule 16.01.2013
comment
Как это им не удалось? Они печатали что-нибудь? Они вызывали исключения? Какой результат вы ожидаете? На какой платформе вы это запускаете? Вы запускаете это в терминале/командной строке, IDLE, Eclipse, что-то еще?   -  person Silas Ray    schedule 16.01.2013
comment
Я использую это на машине с Windows 7 и имею Python 2.7 и запускаю этот код в терминале командной строки. У меня есть вывод, который я получаю ниже: C:\Python27›python Junk.py Gigi DGÇÖAgostino Gigi D?Agostino Gigi D\ u2019Агостино   -  person Prem Minister    schedule 16.01.2013
comment
Я ожидаю, что на выходе будет --Gigi D'Agostino--   -  person Prem Minister    schedule 16.01.2013


Ответы (3)


Вы используете cmd в Windows? В этом случае может быть немного сложно заставить Unicode работать вообще для правильного отображения. Возможно, вы захотите подумать об использовании другого «терминала» для тестирования ваших скриптов. MSYS предоставляет хороший терминал/оболочку, а IDLE включен в дистрибутив Windows Python и имеет оболочку Python (справа). нажмите, открыть в IDLE, F5).

Если вы действительно хотите, чтобы это работало в cmd:

Вы должны установить Lucida Console в качестве шрифта в cmd. Потом:

> chcp
Active code page: 850
> chcp 65001

Тогда у вас должен быть вывод unicode в файле cmd. Ваша «Активная кодовая страница» может отличаться. Обратите внимание, что где-то, потому что вы, возможно, захотите изменить его позже:

> chcp 850

В противном случае вы столкнетесь с другими проблемами (запуск .bat файлов не работает). (См. также batch-file-encoding)

В вашем скрипте вам также нужно это:

import codecs

def cp65001(name):
    """This might be buggy, but better than just a LookupError
    """
    if name.lower() == "cp65001":
        return codecs.lookup("utf-8")

codecs.register(cp65001)

В противном случае питон рухнет. (см. windows-cmd-encoding-change-causes-python-crash)

У меня был аналогичный отчет об ошибке для моего скрипта.


Вы также можете использовать библиотеку для доступа к веб-службе MusicBrainz. Python-musicbrainzngs работает с текущей версией ws/2.

person JonnyJD    schedule 16.01.2013
comment
Хорошая статья, но я не понимаю связи с этим ответом, кроме как о юникоде в Python. - person JonnyJD; 21.01.2013
comment
Я получаю LookupError: неизвестная кодировка: cp65001 - person Prem Minister; 02.02.2013
comment
Похоже, вы забыли часть codecs.register(cp65001). Я также добавил import codecs в пример, чтобы было понятно, откуда берется codecs. - person JonnyJD; 02.02.2013

Экран Unicode работает только со строками Unicode, чтобы преобразовать обычную строку в Unicode, используйте str.decode('unicode-escape'):

In [1]: s='\u0420\u043e\u0441\u0441\u0438\u044f'

In [2]: s
Out[2]: '\\u0420\\u043e\\u0441\\u0441\\u0438\\u044f'

In [3]: s.decode('unicode-escape')
Out[3]: u'\u0420\u043e\u0441\u0441\u0438\u044f'

In [4]: print s.decode('unicode-escape')
Россия

In [5]: s2="Gigi D\u2019Agostino"

In [6]: s2
Out[6]: 'Gigi D\\u2019Agostino'

In [7]: print s2.decode('unicode-escape')
Gigi D’Agostino
person root    schedule 15.01.2013
comment
Интересно, имеет ли это какое-то отношение к моему терминалу командной строки сейчас: - person Prem Minister; 16.01.2013
comment
@PremMinister - как ты это делаешь? если вы скопируете и вставите его в интерактивный интерпретатор Python, он сработает? - person root; 16.01.2013
comment
.decode('unicode-escape') не должен быть необходим для json-текста. - person jfs; 16.01.2013
comment
@ J.F.Sebastian -- Вы, конечно, правы. Я почему-то предположил, что по какой-то причине проблема осталась после использования синтаксического анализатора, потому что как еще он мог бы извлечь строку?... - person root; 16.01.2013
comment
››› s = некоторая\x00строка. с\x15 забавными символами ››› import string ››› filter(lambda x: x in string.printable, s) 'somestring. с забавными персонажами - person Prem Minister; 21.01.2013

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

Например, для анализа данных json:

obj = json.load(urllib2.urlopen(request))

Чтобы красиво напечатать obj без использования escape-последовательности Unicode:

print json.dumps(obj, indent=4, ensure_ascii=False)

Также полезно понимать разницу между:

print unicode_string

И:

print repr(unicode_string)
person jfs    schedule 16.01.2013