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

时间:2011-08-30 11:14:02

标签: python encoding character-encoding

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

I've written a scriptsource on Bitbucket)将Windows Mobile 6短信(通过PIM Backup输出)转换为Android短信(通过SMS Backup & Resotre输入),将PIM备份内容转换为SMSB& R兼容的XML格式。

现在,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()

1 个答案:

答案 0 :(得分:2)

您可以先向我们提供一份您可以阅读并且德国用户无法阅读的PIM备份文件示例。

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

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

您是否阅读过csv docs关于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)
>>>

如果您采取以下步骤,您将有更好的机会实现这一目标:

  1. 读取文件中的原始字节
  2. 使用UTF-16
  3. 将字节字符串解码为Unicode
  4. 以UTF-8
  5. 编码Unicode字符串
  6. 将UTF-8字符串拆分为行列表(使用str.splitlines()
  7. 从该列表中删除csv阅读器
  8. 遍历行,将每个单元格从UTF-8解码为Unicode。
  9. 更新我在您的问题编辑中没有看到任何内容让我改变我之前的建议。您可以选择省略上面的步骤6(这将起作用但是很邪恶)或包括步骤6并重写输出阶段以使用[c]ElementTreelxml来执行UTF-8编码,转义等顺便说一句,你正在编写XML文件,说它们是用UTF-8编码的。我无法重现这个,因为我没有Eclipse,但我怀疑在Eclipse下运行时编写的“OK”的XML文件实际上是在cp1252中编码的。您是否使用XML验证器尝试过它们?

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