我一直在努力解决这个问题,但是使用编码是非常痛苦的,我必须找到更聪明的头脑来寻求帮助。
在我向乌克兰旅行的一次旅行中,一位朋友复制到我的笔中,给我发了一些乌克兰语。但是,正如您所料,在复制到我的计算机的过程中,文件名变得无法读取垃圾,例如:
Ôàíòîì
好吧,我有充分的理由相信原始文件名是使用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 Äâîº Êàï_òîøêà Ïîäèâèñü
答案 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标记。所以为了纠正这个问题,我必须做相反的操作:
为了解码文件名,我使用了以下脚本:
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文件以包含歌曲名称,甚至是文件夹。我发现这比纠正文件名更好,因为这也正确地重命名文件夹并放置对歌曲有意义的文件名。