Tag Archives: Bug

Python JSON模块解码中文的BUG

很多语言或协议选择使用 ASCII 字符 “\”(backslash,0x5c) 作为字符串的转义符,包括 JSON 中的字符串。一般来说,使用 Python 中的 JSON 模块编码英文,不会存在转义符的问题。但如果使用 JSON 模块编解码中文,就可能面临着中文字符包含转义符带来的 bug。本篇文章给出了一个 badcase。

中文解码错误

测试用例文件里面包含繁体的“運動”二字,使用 GB18030 编码。使用 json 解码的错误如下:

$ cat decode.dat
{"a":"運動"}
$ python
>>> import json
>>> fp=open('decode.dat', 'r')
>>> json.load(fp, encoding='gb18030')
Traceback (most recent call last):
  File "", line 1, in 
  File "/home/yangwb/local/lib/python2.7/json/__init__.py", line 278, in load
    **kw)
  File "/home/yangwb/local/lib/python2.7/json/__init__.py", line 339, in loads
    return cls(encoding=encoding, **kw).decode(s)
  File "/home/yangwb/local/lib/python2.7/json/decoder.py", line 360, in decode
    obj, end = self.raw_decode(s, idx=_w(s, 0).end())
  File "/home/yangwb/local/lib/python2.7/json/decoder.py", line 376, in raw_decode
    obj, end = self.scan_once(s, idx)
UnicodeDecodeError: 'gb18030' codec can't decode byte 0xdf in position 0: incomplete
multibyte sequence

发生这个问题的原因,就存在于“運”字的编码之中。“運”的 GB18030 编码是 0xdf5c,由于第二个字符与转义符 “\” 编码相同,所以剩下的这个 0xdf 就被认为是一个 incomplete multibyte sequence。

我本来认为,既然已经提供了编码,json 模块就能够区分汉字与转义符(所以我觉得这应该是 json 的一个 bug)。但从实验来看,并非如此。对于一些不需提供字符编码的 JSON 解码器来说,我们倒可以用一种比较 tricky 的方法绕过上面这个问题,即在“運”字后面加一个额外的转义符:

{"a":"運\動"}

遗憾的是,这种方法对 Python 的 json 模块不适用。我仍不知道该如何解决这个解码问题。

中文编码——没错误!

对于相同的 case,Python 倒是能够编码成功:

$ cat in.dat
運動
$ python
>>> import json
>>> in_str = open('in.dat', 'r').read()
>>> out_f = open('out.dat', 'w', 0)
>>> dump_str = json.dumps({'a': in_str}, ensure_ascii=False, encoding='gb18030')
>>> out_f.write(dump_str.encode('gb18030'))
$ cat out.dat
{"a": "運動"}

所以这件事情就把我给搞糊涂了,Python 的 json 模块不能解码自己编码的 json 串。所以我觉得这可能是一个 bug,或者至少是 2.7.1 版本的 bug。

PS: 要仔细看文档

20120516:经网友 TreapDB 提醒,加载字符串时自己做 Unicode 转换,貌似能够解决这个问题。

$ cat decode.dat
{"a":"運動"}
$ python
>>> import json
>>> in_str = open('decode.dat', 'r').read().decode('gb18030')
>>> json.loads(in_str)

回头仔细看了一下 json 的文档,其中有这么一段:

Encodings that are not ASCII based (such as UCS-2) are not allowed, and should be wrapped with codecs.getreader(encoding)(fp), or simply decoded to a unicode object and passed to loads().

已经注明了 encoding 不支持非 ASCII-based 编码的参数,所以应该使用 getreader 进行转码,而不是让 json 模块去转码。看来是我没读懂文档,大惊小怪了,回家面壁去!

>>> json.load(codecs.getreader('gb18030')(fp))

有关 SVN、Cygwin 和 Notepad++

1. svn 的访问控制

很久以前我就自己配置过 svn 服务器,但总是不能访问成功。到最后还是使用文件系统(即用 file:/// 而不是 svn:// 或其它)访问 svn 仓库,因为自己建立的文件系统不需要认证。

今天我又尝试琢磨了一下我 svn 仓库的设置,才发现之前没配置成功的原因:svn 对用户的权限默认是关闭的。因此当我设置了用户名密码,svn ls 时得到的提示信息仍然是:

svn: Authorization failed

时,我就糊涂了,我的用户名密码没错呀,为啥还是Authorization failed?我还以为是密码设置有问题,没想到除了用户名以外,还得给用户配置访问列表(ACL),否则就什么都访问不了。说简单点儿就是 svn 用户访问控制是一个白名单机制,而我当成了黑名单机制。

知道了错误原因,就很简单了。到与 svnserve.conf 同目录下的 authz 为对应用户添加可以访问的项目就可以了。

2. cygwin 的启动速度

最近发现 cygwin 的启动速度大大变慢,一个终端起来至少要 30 秒。而且不仅仅是启动,所有程序的运行速度都变慢了,比如文件名补全竟然需要好几秒!我忍了很久,就差卸了重装它了,只是想到好不容易配好的各种环境,给忍耐了下来。

今天琢磨了一下 cygwin 的启动过程,发现可以在 bash 命令后加 -x 参数打印所有执行的命令。于是把启动 log 打印出来,查找到引起运行变慢的罪魁祸首:bash_completion。我之前装了一个名叫 bash_completion 的包所谓命令补全的增强包,好家伙,在 /etc/bash_completion.d/ 下面添加了 144 个文件。在启动的时候要一个个 source 这些脚本,怪不得慢呢!

卸载掉这个 bash_completion 包后,cygwin 的运行速度回到了原来的水平,敲命令的时候总算不用憋屈地等补全了。

3. Notepad++ 的中文搜索

使用 2.6.8 版本时,又发现无法搜索中文的 bug。我非常搞不懂 Notepad++ 的作者怎么维护软件质量的,这 bug 在我的印象里就反覆出现两次了。这样的bug都不写一个回归测试用例来检查,实在是有点儿不可思议。无奈之下只好退回到 2.6.7 版本了。

那些搅屎棍儿们

最近在社区或者列表里闲逛,总发现有一些有意思的人,他们根本不懂自己在讨论什么东西,却像行家一样置评,还纠缠不休,像搅屎棍似的,搞得让人抓狂。特摘录几个,以飨大家:

1. 我的朋友王聪的博客

... 谁知道这人怎么回复?第一条回复是问我是不是在说判断endian的技巧?扯淡!你自己的留言什么意思你自己不知道?!第二条回复中他似乎意识到自己前一个回复很白痴,于是补了一句Linux内核中没有。放屁!它有才怪呢!它凭什么要有?!貌似他们家的C语言技巧都是出自Linux内核!一个人能傻到这种地步真的挺不容易的!

别慌。他还能继续向我们证明他更傻呢!这个人在链接中给出了这么个地址,稍微有常识的人都看的出来,那是一个patch,那个patch的作者是Changli Gao,我review了这补丁,认为可以接受,然后Linus回复了,回复的意思也很简单,他不喜欢那个patch,他解释说如果用户程序能触发这个问题就说明你那程序是一坨shit。稍微有常识的人都明白这话什么意思:Linus只不过是借虚构的“你那程序”来说明这个问题不应该在内核中修复。而精彩的事情这时发生了!lovecreatesbeauty@gmail.c0m同学成功地把这话联想到了Linus所说的“你那程序”就是我写的程序!太伟大了!真不知道这人上小学时语文怎么学的?!估计他的语文老师看了都会气得跳楼自杀了!唉,语文没学好也就罢了,你找找整个邮件的存档,看看里面到底有没有shit程序啊。问题是他连找到没找就脑残式地下结论了。没找就没找吧,你仔细看看patch不行么?很不幸,他连patch是谁发的到看不出来!所以这个人不光脑残,眼也有问题,那么大大的一行Signed-off-by他看不到!!...more

2. Ubuntu 的 BUG tracker: Kubuntu 9.04 alpha6 panel corruption

#46 dotancohen wrote on 2009-06-14:

Are you trying to piss him off by any way that you can? You are not a developer, and you go around confirming and invalidating components, and playing ping pong confirmed/invalid with a dev. Then you make a remark like that?!? I personally am angry at you right now. I need this bug fixed, and you are going to piss off the developer so that he leaves us _both_ here to rot.

Go away. File a different bug, you have every right to as the dev implies that your issue is not the same as the OP (yes, that's me). Piss the devs off there. But let them do their work here and help those of us who appreciate it. ...more

简单地来说,就是开发者把该 BUG 标记为 Invalid,说该 BUG 应该是属于 Driver 的 BUG,有个用户不满意开发者对 BUG 的处理,就跟开发者对着干,开发者标记为 Invalid,他重新标记成 Confirmed,开发者开启一个新 BUG 报告,他去给人家改成 Invalid。一般来说修改 BUG 的状态应该是开发者来做,用户可以提交 BUG,assign 给某个开发者,但是不应该修改 BUG 状态,这是一种非常不礼貌的行为。一个用户一般情况下不可能比开发者对目标系统了解更多。

3. WordPress 2.8.x(x<4) 的一个密码重设漏洞

From: laurent gaffie < laurent.gaffie_at_gmail.com >
Date: Tue, 11 Aug 2009 01:11:07 -0400

Mr Fabio,

You dont even understand the bug, so please shut the hell up.

2009/8/11 Fabio N Sarmento [ Gmail ] < fabior2_at_gmail.com >

> if this is an bug, please close Twitter.com, MSN.com and other services,
> because they have the same stupid "Reset password" service.
>
> So please make my day, and create a stupid script to flood with mutiple
> request to reset password. ...more

翻译过来就是,某个人发现了一个 WordPress 2.8.x(x<4) 的密码重设漏洞,报告了出来。有个人评论说:“如果密码重设是 BUG 的话,那么所有网站都有 BUG 了,你没事干就写点儿傻逼程序去到处重设别人的密码吧。”然后报告漏洞的人就无奈了:“你根本没有理解这个 BUG,那么就请闭上你的臭嘴吧。”过了两天,Wordpress 就紧急发布了新版本 2.8.4,fix 了这个 BUG。

于是,我现在非常理解为什么 Linus 大神说话经常那么难听了,要是我成天跟这种人打交道,我也会抓狂。

有些人根本不了解和别人交流、在社区中交流应该遵循什么样的礼仪,应该使用什么样的方法。我遇到过的不礼貌行为包括(但不限于):不去搜索 BUG 列表和邮件列表,一遍又一遍地提出重复的问题;有 BUG 列表和邮件列表时,还直接与开发者联系,或者只 reply 开发者,不知道 reply all 到邮件列表;提交 patch 时,不知道如何使用 diff 和 patch 工具,而是直接提交整个文件;描述 BUG 时,不提供 BUG 出现的环境和步骤,就来一句“xx出问题了”。尽管有时候我都懒的搭理这些人,但是我不想被别人认为是一个没礼貌的人,所以我都尽量回复,但的确心中很不爽。

我希望那些想要在社区中和别人讨论、交流并想赢得别人尊重的朋友能够多了解点儿社区交往的礼仪,起码应该去了解点儿入门的知识,免得遭受挫折打击积极性,反倒以为别人非常不友好不礼貌。推荐的基本资料包括:

1. 如果您想在邮件列表或者社区中提问,那么请首先阅读 “How To Ask Questions The Smart Way ”,中文翻译《提问的智慧

2. 如果您想提交软件 bug, patch, feature request 并想得到开发者的尊重和重视,那么请首先阅读“The Art of Unix Programming” 第 19 章的“Best Practices for Working with Open-Source Developers”。

解决 GAppProxy Set-Cookie 和 HTTPS Cert Bugs

我自己写了一个类似 GAppProxy 的工具,支持 Python 和 PHP,有兴趣可以看这里。 研究 GAppProxy … Continue reading

WordPress 2.8 和 2.8.1 beta1 毛病真多

前两天我才在 Twitter 炫耀了一下我忍住没当小白的努力,没想到昨天晚上被哥们一忽悠,他说他没有发现 WP 2.8 的 bug,就升级了一下 WordPress … Continue reading

vasprintf 会将空间分配到栈上吗?

由于提交过几次 Linux Fetion 的 bug 和 patch,Linux Fetion … Continue reading

笔记本磁盘高频加载/卸载循环问题

注意:本人非硬件专家,下面我仅仅阐述遇到的问题,解决方法,以及我的一些猜想。要仔细的了解这个 BUG,请阅读 Ubuntu Bug 列表的 BUG 59695:High frequency … Continue reading