Преобразование исходной строки байтов в Юникод, не зная кодовой страницы заранее

При использовании контекстного контекстного меню окна пропускают путь к файлу как необработанный (байтовый) тип строки.

Например:

path = 'C:\\MyDir\\\x99\x8c\x85\x8d.mp3'

Многие внешние пакеты в моем приложении ожидают строки типа unicode, поэтому я должен преобразовать их в unicode.

Это было бы легко, если бы мы заранее знали кодировку исходной строки (в примере это cp1255). Однако я не могу знать, какая кодировка будет использоваться локально на каждом компьютере по всему миру.

Как преобразовать string в unicode? Возможно, требуется использовать win32api?

Ответ 1

Не знаю, почему вы можете получить кодовую страницу DOS (862) вместо ANSI (1255) - как настроен параметр правой кнопки мыши?

В любом случае - если вам нужно принять любой произвольный символ Юникода в своих аргументах, вы не сможете сделать это из Python 2 sys.argv. Этот список заполняется из байтов, возвращаемых версией Win32 API, отличной от Unicode (GetCommandLineA), и эта кодировка никогда не защищена от Unicode.

Многие другие языки, включая Java и Ruby, находятся в одной лодке; ограничение исходит из реализаций исполнения Microsoft C стандартных функций библиотеки C. Чтобы исправить это, можно было бы назвать версию Unicode (GetCommandLineW) в Windows вместо того, чтобы полагаться на межплатформенную стандартную библиотеку. Python 3 делает это.

Тем временем для Python 2 вы можете сделать это, вызвав GetCommandLineW самостоятельно, но это не особенно красиво. Вы также можете использовать CommandLineToArgvW, если хотите параметр splattng в стиле Windows. Вы можете сделать это с помощью расширений win32, а также просто ctypes.

Пример (хотя шаг кодирования строки Unicode обратно в байты UTF-8 лучше всего пропустить).

Ответ 2

Обычно я использую собственную функцию утилиты для безопасного преобразования из обычных кодовых страниц в unicode. Для чтения кодировки по умолчанию, вероятно, функция locale.getpreferredencoding может помочь (http://docs.python.org/2/library/locale.html#locale.getpreferredencoding).

Пример функции util, которая пытается преобразовать в unicode путем итерации некоторых предопределенных кодировок:

# coding: utf-8
def to_unicode(s):
    if isinstance(s, unicode): return s

    from locale import getpreferredencoding
    for cp in (getpreferredencoding(), "cp1255", "cp1250"):
        try:
            return unicode(s, cp)
        except UnicodeDecodeError:
            pass
    raise Exception("Conversion to unicode failed")
    # or fallback like:
    # return unicode(s, getpreferredencoding(), "replace")

print (to_unicode("addđšđč枎ŠĐ"))

Откат может быть разрешен с помощью ошибки аргумента функции unicode = "replace". Ссылка http://docs.python.org/2/library/functions.html#unicode

Для преобразования обратно в некоторую кодовую страницу вы можете проверить этот.