Как декодировать строку 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емфира