Python解码适用于我,但不适用于其他人

我确定这个问题已在某处得到解答,但我不知道该搜索什么.我的问题不是别人的问题.简而言之,我有一个带有文本解码的
Python脚本,它对我来说很好解码但对其他用户来说也是如此,即使使用相同的代码和输入也是如此.

I’ve written a script(source on Bitbucket)通过将PIM备份内容转换为兼容SMSB& R的XML格式,将Windows Mobile 6 SMS(通过PIM Backup输出)转换为Android SMSes(通过SMS Backup & Resotre输入).

现在,PIM Backup以UCS-2 Little Endian格式输出其内容,这很好,因为它支持各种国际会话.在我的脚本中,我使用Python的内置字符串解码加载内容并创建一个csv reader对象:

# Read the file contents
sms_text = csv_file.read().decode('utf-16').split(os.linesep)
sms_reader = csv.reader(sms_text, delimiter=';', quotechar='"', escapechar='\\')

然后我处理csv阅读器的每一行:

row = sms_reader.next()

我在try块中有这个,因为当某些东西不太正确时,偶尔它会抛出一个UnicodeEncodeError.但同样,这对我来说非常罕见.

我的问题是,我的脚本的其他用户在他们的短信中使用非ASCII字符似乎几乎总是抛出这个问题.最近一位德国用户联系我说只有大约10%的短信被正确解码.他发送了他的.pib文件,我通过我的脚本运行它,并且转换中没有一个问题.所有的输出似乎都是标准的ANSI / ISO 8859-1 / Windows-1252 /无论如何,所以几乎没有异国情调.

我的问题是,为什么这些用户在我没有问题时使用完全相同的代码(和Python版本)无法解码输入?作为后续行动,我可以做些什么来修改我的脚本以使其适合每个人?

编辑:我没有提到的一个重点是我使用PyDev在Eclipse中运行脚本.当我在命令提示符下运行它时,它会抛出所有与其他人一样的问题!我仍然不知道问题是什么,但希望这有助于缩小范围.

使用非标准字符的非常简单的.csm文件(从.pib文件中提取,名称和数字已更改)的示例如下:

Msg Id;Sender Name;Sender Address;Sender AddressType;Prefix;Subject;Body;BodyType;Folder;Account;Msg Class;Content Length;Msg Size;Msg Flags;Msg Status;Modify Time;Delivery Time;Recipient Nbr;Recipients;Attachment Nbr;Attachments
0x00,0x00;"491703000000";"491703000000";;"";"Wir wünschen dem rainer alles gute und viel gesundheit! Bis nächste woche, wir hören uns bis dahin noch mal.. Liebe grüße aus md!";"";0;"\\%MDF3";"SMS";"IPM.SMStext";;;33;262144;2007,09,23,19,44,32;2007,09,23,19,44,31;1;"851980\;Gela\;+491739000000\;1\;0\;SMS";0;""

然而,通过使用该字符串来准确捕获问题是非常重要的,因为我自己没有遇到异常.

我遇到问题的另一个例子(即使在Eclipse中)如下:

Msg Id;Sender Name;Sender Address;Sender AddressType;Prefix;Subject;Body;BodyType;Folder;Account;Msg Class;Content Length;Msg Size;Msg Flags;Msg Status;Modify Time;Delivery Time;Recipient Nbr;Recipients;Attachment Nbr;Attachments
0x00,0x00;"Jonas/M";"\"Jonas/M\" <+46737000000>";;"";"Den går 28 ";"";2;"\\%MDF4";"SMS";"IPM.SMStext";0;24;0;0;2011,03,12,21,15,19;2011,03,12,21,16,17;0;"";0;""
0x00,0x00;"Don Vär";"\"Don Vär\" <+46709000000>";;"";"försöke® dhdjhdhhdjehdejehţýùhbfvfghjujhuikjkłánjajnxsjajmsxnsmajmkjsnshdjnsjmwkjhdnjsjmwkjdhjjdewjjwjwjw®";"";2;"\\%MDF1";"SMS";"IPM.SMStext";0;212;1;0;2010,05,17,15,56,49;2010,05,17,15,55,46;0;"";0;""

异常回溯是:

Traceback (most recent call last):
  File "C:\Programming\workspace\pim2smsbr\src\pim2smsbr.py", line 207, in <module>
    convert(args.source[0], args.out)
  File "C:\Programming\workspace\pim2smsbr\src\pim2smsbr.py", line 98, in convert
    row = sms_reader.next()
  File "C:\Python27\lib\encodings\cp1252.py", line 12, in encode
    return codecs.charmap_encode(input,errors,encoding_table)
UnicodeEncodeError: 'charmap' codec can't encode character u'\ue403' in position 77: character maps to <undefined> 

更新:

John Machin在下面的回答是一种享受.我只是改变了一条线,这一切都很好.更改:

sms_text = csv_file.read().decode('utf-16').split(os.linesep)

至:

sms_text = csv_file.read().decode('utf-16').encode('utf-8').splitlines()

最佳答案 您可以首先向我们提供您可以阅读并且德语用户无法阅读的PIM备份文件的示例.

偶尔会遇到UnicodeEncodeError(注意Encode not Decode)的事实很重要.注意更改代码以显示您获得的确切错误消息和回溯,而不是抑制它们?

你在Linux / OSX / Windows上运行吗?如果是Windows,在命令提示符窗口中?如果是这样,CHCP命令告诉你什么?它告诉你的德国记者什么?

你有没有看过csv文档对Unicode的看法?这是发生的事情:

>>> import csv
>>> r = csv.reader([u"\xA0"])
>>> r.next()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\xa0' in position 0: ordinal not in range(128)
>>>

如果您采取以下步骤,您将有更好的机会使其工作:

>读取文件中的原始字节
>使用UTF-16将字节字符串解码为Unicode
>以UTF-8编码Unicode字符串
>将UTF-8字符串拆分为行列表(使用str.splitlines())
>从该列表中创建一个csv阅读器
>迭代行,将每个单元格从UTF-8解码为Unicode.

更新我在您的问题编辑中看不到任何内容,以便让我更改以前的建议.您可以选择省略上面的步骤6(这将起作用但是很邪恶)或者包括步骤6并重写输出阶段以使用[c] ElementTree或lxml来执行UTF-8编码,转义等等.顺便说一下,您正在编写XML文件,表示它们是以UTF-8编码的.我无法重现这一点,因为我没有Eclipse,但我怀疑在Eclipse下运行时编写的“OK”的XML文件实际上是在cp1252中编码的.您是否使用XML验证器尝试过它们?

您使用U E403字符的问题只是问题的一部分,您的脚本只能使用csv模块在面对unicode输入时选择的编码中表示的字符“工作”.该字符位于为供应商特定的东西(例如Apple符号)或应用程序内容留出的PUA(私有用户区)块之一.它没有被Python提供的任何编码覆盖,并且无法正确呈现(因为它不是已发布的字体).谷歌搜索(“emoji E403”)并跟随得到的线索表明它可能是U 1F614 PENSIVE FACE,Unicode 6.0中的新功能.

点赞