如何正确处理带有空字节的Python Unicode字符串?

10

问题

看起来 PyWin32 能够返回以空字符结尾的 Unicode 字符串。我想正确地处理这些字符串。

假设我得到一个字符串:u'C:\\Users\\Guest\\MyFile.asy\x00\x00sy',这似乎是一个 C 风格的以 null 结尾的字符串存在 Python Unicode 对象中。我希望将其修剪为常规的字符字符串,例如显示在窗口标题栏中。

在第一个 null 字节处修剪该字符串是否是正确的方法?

我没有预料到会得到这样的返回值,所以我想知道我是否错过了关于 Python、Win32 和 Unicode 如何一起使用的重要信息...或者这只是一个 PyWin32 的 bug。

背景

我正在使用 PyWin32 包中的 Win32 文件选择器函数 GetOpenFileNameW。根据文档,此函数返回一个包含完整文件名路径的 Python Unicode 对象的元组。

当我打开对话框并设置现有路径和文件名时,我得到了奇怪的返回值。

例如,我将默认设置为:C:\\Users\\Guest\\MyFileIsReallyReallyReallyAwesome.asy

在对话框中,我将名称更改为MyFile.asy并单击保存。

返回值的完整路径部分为:u'C:\Users\Guest\MyFile.asy\x00wesome.asy'

我期望它是:u'C:\\Users\\Guest\\MyFile.asy'

该函数返回一个未修剪终止字节的重复使用的缓冲区。不用说,我的代码的其余部分没有为处理 C 风格的以 null 结尾的字符串进行设置。

演示代码

以下代码演示了从 GetSaveFileNameW 的返回值中获取 null-terminated 字符串。

操作步骤:在对话框中将文件名更改为“ 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),则字符串将完整输出而不包含null字节。

环境

Windows 7 Professional 64位(无服务包),Python 2.7.1,PyWin32 Build 216

更新:PyWin32跟踪工件

根据我收到的评论和答案,这很可能是一个pywin32 bug,因此我提交了一个跟踪工件

更新2:已修复!

Mark Hammond在跟踪工件中报告说,这确实是一个bug。修复程序已经检入f3fdaae5e93d版本,因此希望下一个发行版会解决该问题。

我认为Aleksi Torhamo在下面的答案是PyWin32修复之前版本的最佳解决方案。


+1 哦,看起来你发现了一个 PyWin32 的 bug! - Katriel
我已经给Mark Hammond(主要的PyWin32维护者)发送了一封简短的便条,引用了这个页面。 - Tom Zych
@Tom 谢谢!我还在这里提交了一个跟踪器工件:https://sourceforge.net/tracker/?func=detail&aid=3277647&group_id=78018&atid=551954 - Steven T. Snyder
3个回答

6
我认为这是个bug。正确的处理方式应该修复pywin32,但是如果你不够冒险,可以简单地将其修剪掉。
你可以使用filename.split('\x00', 1)[0]获取第一个'\x00'之前的所有内容。

你说得对,PyWin32的维护者Mark Hammond确认这是一个bug,已在Rev f3fdaae5e93d中修复了它,所以我认为它应该会在下一个发布版本中解决。请参阅https://sourceforge.net/tracker/?func=detail&aid=3277647&group_id=78018&atid=551954。 - Steven T. Snyder

2

在我测试的PyWin32/Windows/Python版本中,没有出现这种情况;即使返回的字符串非常短,我也不会得到任何空值。您可以调查一下上述软件的新版本是否修复了此问题。


你的配置是什么?我正在使用Windows 7 Pro(没有服务包),Python 2.7.1和PyWin32 Build 216(最新版本)。 - Steven T. Snyder
我正在使用相同的PyWin32版本,在Windows 7 Enterprise x64上运行Python 2.6.5。也许这是32位与64位的问题? - Nicholas Riley
实际上,我也在使用64位Windows。但是我没有使用64位的Python版本。 - Steven T. Snyder
啊哈,可能就是这个问题。我正在使用64位Python(和Win 7 SP1,我忘了提)。无论如何,听起来肯定是值得报告的PyWin32问题。 - Nicholas Riley

0

我记得几年前遇到过这个问题,后来我发现这样的Win32文件名对话框相关函数返回一个序列'filename1\0filename2\0...filenameN\0\0',其中包括取决于Windows分配的缓冲区可能有的垃圾字符。

现在,您可能更喜欢列表而不是原始返回值,但那将是一个RFE,而不是错误。

附言:当我遇到这个问题时,我很清楚为什么人们会期望GetOpenFileName可能返回一个文件名列表,而我无法想象为什么GetSaveFileName会这样做。也许这被认为是API的统一性。反正我又不知道。


你好ΤΖΩΤΖΙΟΥ,多个文件名选择的空值分隔序列是有文档记录的行为,所以这并不是一个问题。我问题描述中提到的问题是单个文件名选择时出现的。在这种情况下,我不希望有空字符,因为文档说返回值将是“完整路径”。我为该错误提交了跟踪工件,并已在开发代码中修复,同时澄清了文档。 - Steven T. Snyder

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接