恢复编码错误的文件名

时间:2015-08-22 15:13:49

标签: python unicode decode encode cp1251

我一直在努力解决这个问题,但是使用编码是非常痛苦的,我必须找到更聪明的头脑来寻求帮助。

在我向乌克兰旅行的一次旅行中,一位朋友复制到我的笔中,给我发了一些乌克兰语。但是,正如您所料,在复制到我的计算机的过程中,文件名变得无法读取垃圾,例如:

Ôàíòîì

好吧,我有充分的理由相信原始文件名是使用CP1251编码的(我知道这是因为我手动检查了编码表并设法正确翻译了乐队的名称)。显而易见的是,在复制过程中,CP1251代码保存在哪里,操作系统现在只将它们解释为Unicode代码。

我尝试使用以下脚本“解释”Python中的代码:

print u"Ôàíòîì".decode('cp1251')

虽然感觉不对。结果也是完全垃圾:

Ôàíòîì

如果我这样做:

print repr(u"Ôàíòîì".decode('cp1251'))

我获得:

u'\u0413\u201d\u0413\xa0\u0413\xad\u0413\u0406\u0413\xae\u0413\xac'

我发现如果我可以获得Unicode中的所有代码点并将它们偏移0x350,我会将它们放在乌克兰西里尔语的正确位置。但我不知道该怎么做,可能有一个答案在概念上比这更正确。

非常感谢任何帮助!

编辑:以下是正确翻译的示例

Ôàíòîì应该翻译成Фантом。

Ô 0x00D4 -> Ф 0x0424
à 0x00E0 -> а 0x0430
í 0x00ED -> н 0x043D
ò 0x00F2 -> т 0x0442
î 0x00EE -> о 0x043E
ì 0x00EC -> м 0x043C

正如我之前所说,正确和错误的代码点之间存在0x0350偏移。

(好吧,这些文件是音乐文件......我想你怀疑......)

其他一些测试字符串(我不知道其翻译):     Áåçêîíò>îëfl     Äâîº     Êàï_òîøêà     Ïîäèâèñü

4 个答案:

答案 0 :(得分:3)

postDelayed

如果你看一下你的样本中的个别角色,他们中的大多数来自西里尔语,但你有其他来自希腊语和科普特语,拉丁语扩展B和u'fe52'是从后面的一个句号。所以这有点乱 编辑:

  
    
      

a =u'Ôàíòîì'.encode('cp1252')。decode('cp1251')
      打印一个           Фантом
      a =u'Ä⺺Êàï_òîøêà'.encode('cp1252')。decode('cp1251')
      打印一个           ДвоєКап_тошка
      a =u'Ïîäèâèñü'.encode('cp1252')。decode('cp1251')
      打印一个           Подивись
      a =u'Áåçêîíò>îë'.encode('cp1252')。decode('cp1251')
      打印一个           Безконт>ол

    
  

cp1252适用于给定的样本,但>>> a = u'Ôàíòîì'.encode('8859').decode('cp1251') >>> print a Фантом 除外,其中拉丁语小Ligature Fl U + FB02似乎是多余的

答案 1 :(得分:1)

你可以像这样添加这个0x350偏移量:

Python 2:

>>> s = u'Ôàíòîì'
>>> decoded = u''.join([unichr(ord(c)+0x350) for c in s])
>>> print decoded
Фантом

答案 2 :(得分:1)

>>> u'Ôàíòîì'.encode('latin1').decode('cp1251')
'Фантом'

答案 3 :(得分:1)

我发现除了文件名之外,我的所有文件都有错误编码的元数据。

我发现mp3文件的id3元数据标准只支持latin1,utf8和utf16编码。

我的文件都包含在mp3文件中设置为latin1的CP1251数据。可能在俄罗斯和西里尔文写作国家,所有音乐播放器都应该理解latin1应该被解释为CP1251,而对我来说情况并非如此。

我使用Python和mutagen来纠正元数据。当读取mp3元数据时,mutagen假设数据被编码为latin1,结果显示乱码。我必须做的是获取那些乱码,再次将它们编码为latin1并解码为CP1251,获得unicode。然后我覆盖了mp3元数据,然后mutagen理解了unicode应该保存为utf-8。因此,所有元数据都是正确的。

要更正文件元数据,我使用了以下Python脚本:

from mutagen.easyid3 import EasyID3

def decode_song_metadata(filename):
    id3 = EasyID3(filename)
    for key in id3.valid_keys:
        val = id3.get(key)
        if val:
            print key
            decoded = val[0].encode('latin1').decode('cp1251')
            print decoded
            id3[key] = decoded
    id3.save()

def correct_metadata():
    paths = [u'/Users/felipe/Downloads/Songs']    

    for path in paths:
        print 'path: ' + decode_filename(path)
        for dirpath, dirnames, filenames in os.walk(path):
            for filename in filenames:
                try:
                    decode_song_metadata(os.path.join(dirpath, filename))
                except:
                    print filename


if __name__ == '__main__':
    correct_metadata()

这更正了mp3元数据,但是更正文件名需要一个不同的技巧,因为它们有一个不同的编码问题。我认为发生的事情是原始文件名在CP1251中,但当它们从我的fat32格式的usb-stick复制到我的Mac时,macOS将文件名解释为latin1。这个带有奇怪重音字符的原始文件名在UTF-16中以“Normal Form Decomposed”编码,其中每个重音都保存为与主字母不同的unicode字符。此外,macOS添加了一个污染文件名的BOM标记。所以为了纠正这个问题,我必须做相反的操作:

  • 获取文件名。这将返回一个unicode字符串,该字符串在Normal Form Decomposed中使用拉丁文重音字符。
  • 我们必须再次转换为Normal Form Composed。
  • 然后我们用UTF-16编码。
  • 我们删除了BOM。
  • 我们将解释解码为CP1251。

为了解码文件名,我使用了以下脚本:

def decode_filename(filename):
    # MacOS filenames are stored in Unicode in "Normal Form Decomposed"
    # form, where the accents are saved separated from the main
    # character. Because the original characters weren't proper
    # accentuated letters, in order to recover them we have to decompose
    # the filenames.
    # http://stackoverflow.com/a/16467505/212292
    norm_filename = unicodedata.normalize('NFC', filename)
    utf16 = norm_filename.encode('utf16')
    bom = codecs.BOM_UTF16

    if utf16.startswith(bom):
        # We have to remove the BOM bytes
        utf16 = utf16[len(bom):]

    cp1251 = utf16.decode('cp1251')
    return cp1251

这应该与运行os.walk()方法返回的unicode一起使用。

虽然上面的脚本有效但我最终没有用它来纠正文件名。我正在使用启用了“自动管理器”功能的iTunes。这很棒,因为我每次都会在iTunes上播放一首歌,它会获得mp3元数据(我已经使用上面的第一个脚本更正了)并重命名mp3文件以包含歌曲名称,甚至是文件夹。我发现这比纠正文件名更好,因为这也正确地重命名文件夹并放置对歌曲有意义的文件名。