使用Python和mutagen去摩擦

Dmi*_*sky 2 python unicode encoding mutagen mojibake

我正在阅读mojibaked ID3标签mutagen.我的目标是在学习编码和Python的处理时修复mojibake.

我正在使用的文件有一个ID3v2标签,我正在看它的album(TALB)帧,根据TALBID3帧中的编码字节,用Latin-1(ISO-8859-1)编码.我知道这个帧中的字节是用cp1251(西里尔语)编码的.

到目前为止,这是我的代码:

 >>> from mutagen.mp3 import MP3
 >>> mp3 = MP3(paths[0])
 >>> mp3['TALB']
 TALB(encoding=0, text=[u'\xc1\xf3\xf0\xe6\xf3\xe9\xf1\xea\xe8\xe5 \xef\xeb\xff\xf1\xea\xe8'])
Run Code Online (Sandbox Code Playgroud)

现在,正如您所看到的,mp3['TALB'].text[0]此处表示为Unicode字符串.然而,它是mojibaked:

 >>> print mp3['TALB'].text[0]
 Áóðæóéñêèå ïëÿñêè
Run Code Online (Sandbox Code Playgroud)

我很难将这些cp1251字节转码为正确的Unicode代码点.到目前为止,我最好的结果非常不合适:

>>> st = ''.join([chr(ord(x)) for x in mp3['TALB'].text[0]]); st
'\xc1\xf3\xf0\xe6\xf3\xe9\xf1\xea\xe8\xe5 \xef\xeb\xff\xf1\xea\xe8'
>>> print st.decode('cp1251')
?????????? ?????? <-- **this is the correct, demojibaked text!**
Run Code Online (Sandbox Code Playgroud)

据我了解这种方法,它的工作原理是因为我最终将Unicode字符串转换为8位字符串,然后我可以将其解码为Unicode,同时指定我正在解码的编码.

问题是我不能decode('cp1251')直接在Unicode字符串上:

>>> st = mp3['TALB'].text[0]; st
u'\xc1\xf3\xf0\xe6\xf3\xe9\xf1\xea\xe8\xe5 \xef\xeb\xff\xf1\xea\xe8'
>>> print st.decode('cp1251')
Traceback (most recent call last):
  File "<console>", line 1, in <module>
  File "/Users/dmitry/dev/mp3_tag_encode_convert/lib/python2.7/encodings/cp1251.py", line 15, in decode
    return codecs.charmap_decode(input,errors,decoding_table)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-9: ordinal not in range(128)
Run Code Online (Sandbox Code Playgroud)

有人可以解释一下吗?我无法理解如何ascii直接在u''字符串上操作时不将其解码为7位范围.

Fre*_*nan 5

首先,使用您知道它已经存在的编码对其进行编码.

>>> tag = u'\xc1\xf3\xf0\xe6\xf3\xe9\xf1\xea\xe8\xe5 \xef\xeb\xff\xf1\xea\xe8'
>>> raw = tag.encode('latin-1'); raw
'\xc1\xf3\xf0\xe6\xf3\xe9\xf1\xea\xe8\xe5 \xef\xeb\xff\xf1\xea\xe8'
Run Code Online (Sandbox Code Playgroud)

然后你可以用正确的编码解码它.

>>> fixed = raw.decode('cp1251'); print fixed
?????????? ??????
Run Code Online (Sandbox Code Playgroud)

  • 它失败是因为'u''.decode(enc)`与`u'相同.codes(sys.getdefaultencoding()).decode(enc)`和`sys.getdefaultencoding()`几乎总是`= ='ascii'. (2认同)