Как декодировать строку cp1252?

Я получаю тег mp3 (ID V1) с eyeD3 и хотел бы понять его кодировку. Вот что я пытаюсь:

>>> print(type(mp3artist_v1))
<type 'unicode'>

>>> print(type(mp3artist_v1.encode('utf-8')))
<type 'str'>

>>> print(mp3artist_v1)
Zåìôèðà

>>> print(mp3artist_v1.encode('utf-8').decode('cp1252'))
Zåìôèðà 

>>> print(u'Zемфира'.encode('utf-8').decode('cp1252'))
Zемфира

Если я использую онлайн-инструмент для декодирования значения, он говорит, что значение Zемфира может быть преобразовано в правильное значение Zемфира изменяя кодировки CP1252 → UTF-8 и значение Zåìôèðà изменяя кодировки как CP1252 → CP1251,

Что я должен сделать, чтобы получить Zемфира от mp3artist_v1? .encode('cp1252').decode('cp1251') работает хорошо, но как я могу понять возможную кодировку автоматически (возможно только 3 кодировки - cp1251, cp1252, utf-8? Я планировал использовать следующий код:

def forceDecode(string, codecs=['utf-8', 'cp1251', 'cp1252']):
    for i in codecs:
        try:
            print(i)
            return string.decode(i)
        except:
            pass
    print "cannot decode url %s" % ([string]) 

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

1 ответ

Решение

Это

s = u'Zåìôèðà'
print s.encode('latin1').decode('cp1251')
# Zемфира

Объяснение: Zåìôèðà ошибочно рассматривается как строка в кодировке Юникод, в то время как на самом деле это последовательность байтов, что означает Zемфира в cp1251. Применяя encode('latin1') мы преобразуем эту строку "Юникод" обратно в байты, используя номера кодовых точек в качестве байтовых значений, а затем преобразуем эти байты обратно в Юникод, сообщая декодеру, что мы используем cp1251.

Что касается автоматического декодирования, следующий подход грубой силы, кажется, работает с вашими примерами:

import re, itertools

def guess_decode(s):
    encodings = ['cp1251', 'cp1252', 'utf8']

    for steps in range(2, 10, 2):
        for encs in itertools.product(encodings, repeat=steps):
            r = s
            try:
                for enc in encs:
                    r = r.encode(enc) if isinstance(r, unicode) else r.decode(enc)
            except (UnicodeEncodeError, UnicodeDecodeError) as e:
                continue
            if re.match(ur'^[\w\sа-яА-Я]+$', r):
                print 'debug', encs, r
                return r

print guess_decode(u'Zемфира')
print guess_decode(u'Zåìôèðà')
print guess_decode(u'ZåìôèðÃ\xA0')

Результаты:

debug ('cp1252', 'utf8') Zемфира
Zемфира
debug ('cp1252', 'cp1251') Zемфира
Zемфира
debug ('cp1252', 'utf8', 'cp1252', 'cp1251') Zемфира
Zемфира
Другие вопросы по тегам