Как обрабатывать строки юникода Python с нулевым байтом "правильный"?

Вопрос

Кажется, что PyWin32 удобен тем, что в качестве возвращаемых значений передаются строки unicode с нулевым символом. Я хотел бы иметь дело с этими строками как "правильный".

Скажем, я получаю строку вроде: u'C:\\Users\\Guest\\MyFile.asy\x00\x00sy'. Кажется, что это строка с нулевым символом C-стиля, которая висит в объекте юникода Python. Я хочу подрезать этого плохого мальчика до обычной последовательности символов, которые я мог бы, например, отобразить в строке заголовка окна.

Является ли обрезка строки в первом нулевом байте правильным способом справиться с ней?

Я не ожидал получить возвращаемое значение, подобное этому, поэтому я задаюсь вопросом, не хватает ли я чего-то важного в том, как Python, Win32 и Unicode играют вместе... или если это всего лишь ошибка PyWin32.

Фон

Я использую функцию выбора файлов Win32 GetOpenFileNameW из пакета PyWin32. Согласно документации, эта функция возвращает кортеж, содержащий полный путь имени файла, как объект Unicode Python.

Когда я открываю диалог с существующим набором путей и файлов, я получаю странное возвращаемое значение.

Например, у меня был набор по умолчанию: C:\\Users\\Guest\\MyFileIsReallyReallyReallyAwesome.asy

В диалоговом окне я изменил имя на MyFile.asy и нажал кнопку "Сохранить".

Полная часть пути возвращаемого значения: u'C:\Users\Guest\MyFile.asy\x00wesome.asy'`

Я ожидал, что это будет: u'C:\\Users\\Guest\\MyFile.asy'

Функция возвращает возвращенный буфер без обрезания завершающих байтов. Излишне говорить, что остальная часть моего кода не была настроена для обработки строки с нулевым завершением в стиле C.

Демо-код

Следующий код демонстрирует строку с нулевым завершением в возвращаемом значении из GetSaveFileNameW.

Направления: В диалоговом окне измените имя файла на "MyFile.asy", затем нажмите "Сохранить". Соблюдайте, что напечатано на консоли. Выход, который я получаю, равен u'C:\\Users\\Guest\\MyFile.asy\x00wesome.asy'.

import win32gui, win32con

if __name__ == "__main__":
    initial_dir = 'C:\\Users\\Guest'
    initial_file = 'MyFileIsReallyReallyReallyAwesome.asy'
    filter_string = 'All Files\0*.*\0'
    (filename, customfilter, flags) = \
        win32gui.GetSaveFileNameW(InitialDir=initial_dir,
                    Flags=win32con.OFN_EXPLORER, File=initial_file,
                    DefExt='txt', Title="Save As", Filter=filter_string,
                    FilterIndex=0)
    print repr(filename)

Примечание. Если вы недостаточно сократите имя файла (например, если вы попробуете MyFileIsReally.asy), строка будет завершена без нулевого байта.

Окружающая среда

64-разрядный Windows 7 Professional (без пакета обновления), Python 2.7.1, PyWin32 Build 216

UPDATE: Артефакт Tracker PyWin32

Основываясь на комментариях и ответах, которые я получил до сих пор, это, вероятно, ошибка pywin32, поэтому я подал артефакт трекера.

ОБНОВЛЕНИЕ 2: Исправлено!

Марк Хэммонд сообщил в артефакте трекера, что это действительно ошибка. Исправление было проверено на rev f3fdaae5e93d, поэтому, надеюсь, это сделает следующий выпуск.

Я думаю, что Алекси Торхамо ответ ниже - лучшее решение для версий PyWin32 до исправления.

Ответ 1

Я бы сказал, что это ошибка. Правильный способ справиться с этим, вероятно, будет исправлять pywin32, но если вы не чувствуете себя достаточно предприимчивым, просто обрезайте его.

Вы можете получить все до первого '\x00' с помощью filename.split('\x00', 1)[0].

Ответ 2

Это не происходит в тестируемой версии PyWin32/Windows/Python I; Я не получаю никаких нулей в возвращаемой строке, даже если она очень короткая. Вы можете выяснить, исправлена ​​ли более новая версия одного из указанных выше ошибок.

Ответ 3

ISTR, что у меня была эта проблема несколько лет назад, я обнаружил, что такие функции, связанные с именем файла Win32 с именем файла, возвращают последовательность 'filename1\0filename2\0...filenameN\0\0', включая возможные символы мусора в зависимости от того, какой буфер выделяется Windows.

Теперь вы можете предпочесть список вместо необработанного возвращаемого значения, но это будет RFE, а не ошибка.

PS Когда у меня возникла эта проблема, я понял, почему можно ожидать, что GetOpenFileName возможно вернет список имен файлов, в то время как я не мог себе представить, почему GetSaveFileName будет. Возможно, это считается единообразием API. Кто бы я знал, во всяком случае?