2015-08-22 2 views
0

Я немного борюсь с этой проблемой, но работа с кодировкой настолько болезненна, что я должен прийти к вашим умным умом для некоторой помощи.Восстановление имен файлов с плохой кодировкой

В поездке, которую я совершил в Украину, друг, скопированный в мое перо, привел мне некоторые украинские именованные файлы. Однако, как и следовало ожидать, в процессе копирования на компьютере имена файлов стало невозможно читать мусор, например, это:

Ôàíòîì 

Ну, у меня есть веские основания полагать, что исходные имена файлов были кодирование с использованием 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 Я бы разместил их в правильном месте для украинской кириллицы. Но я не знаю, как это сделать, и, вероятно, есть ответ, который более концептуально правильный, чем этот.

Любая помощь была бы принята с благодарностью!

Edit: Вот пример правильного перевода

Ôàíòîì следует перевести на Фантом.

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

Как я уже говорил ранее, между правильными и неправильными кодовыми точками существует смещение 0x0350.

(ОК, файлы будут музыкальные файлы ... Я думаю, вы подозревали, что ...)

Некоторые другие тестовые строки (перевод которого я не знаю): Aac êîíò> Т.е фл Äâîº Êàï_òîøêà Ïîäèâèñü

+0

Возможный дубликат http://stackoverflow.com/questions/7555335/how-to-convert-a-string-from-cp1251-to-utf8 – saulspatz

+0

Это не CP1251; он выглядит как многобайтовый [Mojibake] (https://en.wikipedia.org/wiki/Mojibake); у вас был UTF-8 или аналогичный, и он был декодирован неправильно. Вы можете увидеть, может ли библиотека '' ftfy' (http://ftfy.readthedocs.org/en/latest/) сделать что-нибудь из этого. Это невозможно для образца, который вы дали. –

+0

Можете ли вы поделиться с нами ожидаемым значением? Затем мы можем попытаться вернуться назад, чтобы увидеть, как Mojibake был создан и изменить процесс. И учтите, что байты могут быть * отброшены *, поскольку они не отображаются на печатные символы. Дайте нам вывод 'print repr (value)' output, а не вывод 'print value ', чтобы мы здесь делали что-либо значимое. –

ответ

0

I found out that, besides the fi lenames, all my files had incorrectly encoded metadata.

I found out that the id3 metadata standard for mp3 files only supports latin1, utf8 and utf16 encodings.

My files all contained CP1251 data that were set as latin1 on the mp3 files. Probably in Russia and cyrillic-writing countries all music players are set to understand that latin1 should be interpreted as CP1251, which was not the case for me.

I used Python and mutagen for correcting the metadata. When reading the mp3 metadata, mutagen assumed that the data was encoded as latin1, showing garbled characters as a result. What I had to do was to get those garbled characters, encode them into latin1 again AND decode as CP1251, obtaining unicode. Then I overwrote the mp3 metadata and mutagen understood then that the unicode should be saved as utf-8. With that all the metadata was correct.

To correct the files metadata I used the following Python script:

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() 

This corrected the mp3 metadata, however correcting the filenames required a different trick, because they had a differend encoding problem. What I think happend was that the original filenames were in CP1251, but when they were copied from my fat32 formatted usb-stick to my Mac, macOS interpreted the filenames as latin1. This originated filenames with weird accented characters, which were encoded in UTF-16 in "Normal Form Decomposed", where each accent is saved as a different unicode character than the main letter. Also macOS added a BOM marker that polluted the filename. So in order to correct this I had to do the reverse operation:

  • get the filename. This returns a unicode string which latin accented characters in the Normal Form Decomposed.
  • we have to convert again to Normal Form Composed.
  • then we encode in UTF-16.
  • we remove the BOM.
  • we decode interpreting as 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().

Хотя приведенный выше сценарий работает, я не использовал его для исправления имен файлов. Я использовал iTunes с включенной функцией «Автоорганизатор». Это было здорово, потому что каждый раз, когда я играл в iTunes, он получал метаданные mp3 (которые я уже исправил с использованием первого скрипта выше) и переименовал mp3-файл, чтобы содержать имя песни и даже папку. Я нахожу это лучше, чем исправление имен файлов, потому что это также правильно переименовывает папки и помещает имена файлов, которые имеют смысл для песни.

0

Вы можете добавить 0x350 смещение так:

Python 2:

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

Ничего себе это работает! Но я бы хотел использовать ответ на кодировку/декодирование, чтобы решить эту проблему ... –

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

Мне этот вопрос нравится. Он работает со строкой «Фантом», но когда я перехожу к следующему, он не может преобразовать некоторые символы. Например, этот: «Áåç êîíò> îë fl» возвращает ошибку, но если я удалю символы «>» и «fl», это переводит на: «Без контол» (что кажется правильным, минус некоторые удаленные символы). –

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

Если посмотреть на отдельных персонажей в ваших образцах большинство из них происходят из кириллицы, но у вас есть другие там с греческого и коптского, Расширенная латиница B и u'fe52' является полной остановке от сзади. Так что это немного беспорядок.
EDIT:

a = u'Ôàíòîì'.encode ('cp1252'). Decode ('cp1251')
print a
Фантом
a = u'Äâîº Êàï_òîøêà " .encode ('cp1252'). decode ('cp1251')
print a
Двое Кап_тошка
a = u'Ïîäèâèñü'.encode ('cp1252'). decode ('cp1251')
print a
Посмотри
a = u'Áåç êîíò> îë'.encode ('cp1252'). Decode ('cp1251')
print a
Без конт> ол

cp1252 works for the given samples, except for Áåç êîíò›îëfl where the Latin Small Ligature Fl U + FB02 appears to be superfluous

Смежные вопросы