如何解码cp1252字符串?

4 投票
1 回答
18427 浏览
提问于 2025-04-18 04:29

我正在使用eyeD3获取一个mp3标签(ID V1),想要了解它的编码方式。以下是我尝试的内容:

>>> 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емфира可以通过改变编码方式从CP1252 → UTF-8转换为正确的值Zемфира,而值Zåìôèðà则可以通过改变编码方式为CP1252 → CP1251来转换。

我应该怎么做才能从mp3artist_v1中得到Zемфира呢?.encode('cp1252').decode('cp1251')这个方法效果不错,但我该如何自动识别可能的编码呢(只有三种编码可能:cp1251cp1252utf-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 个回答

6

这个

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

解释:Zåìôèðà 被错误地当作了一个unicode字符串,但其实它只是一个字节序列,代表的是在cp1251编码下的Zемфира。通过使用encode('latin1'),我们把这个“unicode”字符串转换回字节,实际上是用字符的编码值作为字节值,然后再把这些字节转换回unicode,告诉解码器我们用的是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емфира

撰写回答