4

我已经为这个问题苦苦挣扎了一段时间,但是使用编码非常痛苦,我不得不求助于你更聪明的头脑来寻求帮助。

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

Ôàíòîì

好吧,我有充分的理由相信原始文件名是使用 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 偏移。

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

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

4

4 回答 4

5
>>> a = u'Ôàíòîì'.encode('8859').decode('cp1251')   
>>> print a   
Фантом    

如果您查看样本中的单个字符,其中大多数来自西里尔字母,但其中还有其他来自希腊语和科普特语、拉丁语扩展 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 适用于给定的样本,除了Áåç êîíò›îëfl拉丁小连字 Fl U+FB02 似乎是多余的

于 2015-08-22T16:05:39.117 回答
3

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

我发现 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 棒复制到我的 Mac 时,macOS 将文件名解释为 latin1。这起源于带有奇怪重音字符的文件名,这些文件名在“正常形式分解”中以 UTF-16 编码,其中每个重音都保存为与主字母不同的 unicode 字符。macOS 还添加了一个污染文件名的 BOM 标记。所以为了纠正这个我不得不做相反的操作:

  • 获取文件名。这将返回一个 unicode 字符串,其中分解了范式中的拉丁重音字符。
  • 我们必须再次转换为 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 文件以包含歌曲名称,甚至文件夹。我发现这比更正文件名更好,因为这也会正确重命名文件夹并放置对歌曲有意义的文件名。

于 2017-06-14T17:14:16.297 回答
1
>>> u'Ôàíòîì'.encode('latin1').decode('cp1251')
'Фантом'
于 2015-08-22T15:57:16.410 回答
1

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

蟒蛇2:

>>> s = u'Ôàíòîì'
>>> decoded = u''.join([unichr(ord(c)+0x350) for c in s])
>>> print decoded
Фантом
于 2015-08-22T15:52:34.237 回答