编程

今天找到了一直想要的 Firefox 扩展

从昨晚开始,我正式把电脑的默认浏览器修改回了 Firefox。经过了前几日对 Vivaldi 的(无效)探索,我对标签页的管理略微产生了一点兴趣。于是今天搜索了一下 Firefox 的扩展,找一下跟标签页有关的,结果找到了这个——Tab Stash

它的功能是可以把一些标签页分组、命名、隐藏、保存,可以达到节省资源等功能。在我目前使用的电脑上,打开很多标签不会成为电脑资源的拖累,因此我更加在意的是标签的保存功能,如果可以多设备同步就更好了。我目前在用的是 Tab Session Manager 扩展,可以登录 Google 账号来进行多设备同步。它工作的不错,以至于我没有发现 Firefox 自己已经添加了标签页多设备同步的功能了。今天我看到介绍,Tab Stash 可以把标签组的标签的连接都通过纯文本进行复制,就产生了兴趣,于是安装了它。

经过一番测试,我惊喜的发现 Tab Stash 可以选择导出标签链接的格式,可以导出成 Markdown 格式太有用了,我把它复制到一个 md 文档里面,就相当于在本地保存了一份收藏夹,可以进行分类编辑等各种操作不受影响。

这个功能在今天来说意义已经少了很多了。对我来说,最看中这个功能是在电脑还没有那么好的时代。我上大学期间,电脑的配置不高,我的浏览习惯又是在后台打开好几十个标签,而且不关电脑,上学、回家都是直接一扣盖子,休眠到下一个地方打开继续看,几十个标签页要看好多天。这种情况下,一但要重启、关闭浏览器就会很麻烦,这些标签页关闭后,要再次找回来,去历史记录里一点一点找可太麻烦了。那个时候 Del.icio.us 已经没了,本地收藏夹我又基本不用,也不放心,于是我主要是保存在我的维基页面里。手动把链接按照维基的语法来修改很麻烦,我经过研究,写过两个版本的脚本,来自动化完成这个功能。一开始应该是 Ruby 脚本,后来是 AppleScript,还是反过来,我记不清了。作用是把当前活动的浏览器窗口里所有的标签页,按照维基的格式,把标题和链接输出来,这样就可以复制后粘贴进维基页面里。后来随着浏览器的更新,我也没有及时同步这个脚本,也就荒废了。

今天看到 Tab Stash 这个功能,我立刻感觉这个脚本安装的值。虽然它还不能导出 MediaWiki 或者其他维基格式的链接,但我现在也不急需,而且能导出 Markdown 已经很不错了,至少可以转换不是么。

迟钝的编程

从上周一开始,我接到了一个任务,又是把系统里导出来的数据进行统计,输出结果。我用 Ruby 语言编写了一个简单的程序,来处理 Excel 导出的 CSV 文件。由于时间紧急,我没有仔细构思程序应该怎么设计,直接想到什么写什么,最终写出了程序,完成了任务。

之后的几天,我每天开心的用我的小程序来完成任务。尽管我心里想着为它加上直接解析 Excel 的功能,省得我要手动把文件导出成 CSV 格式。不过尝试了一下 parseexcel 包没有成功之后,我暂时就偃旗息鼓了。然后一直到了这周一,领导找到我,说数据不对,我一看果然差的很多,心里一下子紧张起来。然后手动计算,找问题出在哪里。结果发现原来从三天前,信息中心的人不声不响在系统输出的数据表里加了一列,我的程序当然出错了。于是急忙改正。

之后这周三我因为请假,于是就在周二下班后,把当天的结果给弄了出来。我们公司每天下午 4 点就结帐,停止生成新订单了,我觉得到了下班后来弄这个表应该万无一失(过去是次日得出本日的结果)。岂料到了周三下午,领导找到我说数据又不对。我心想怎么回事儿?结果领导指着一个相差比较大的数据给我看。我一看正好有印象,因为我前一天导出数据后,看到这家分部的数据量特别小,只有不到 20 行——这些数据无论如何不能得到领导算出的 80 多的结果。于是我重新导出数据,悲愤的发现原来下班后 1 小时后数据还没有计算完毕,所以发生了这种错误。

然后领导带着我一起手工算了一下,我在这个过程中发现了,原来系统导出的数据有各种各样的坑,一些不适合的数据也被放了进去。另外,我还发现了另外一种情况,也应该被算入结果之中,结果一开始因为它没有出现过,因此我就忽略了它,导致我得到的结果与正确结果有偏差。

于是,从前天下午下班后,我就一个人留在办公室,思考这个问题。因为我的思路还是一开始的那样,所以陷入了一个死胡同中。一开始我是让程序直接模拟我思考的过程,心里怎么想的就让它怎么运行,结果是它完全模拟了一个人类的处理过程。有了不同的情况之后,程序需要判断各种不同的情况,按照这个思路,最简单的方法是程序在读取完一遍数据文件后,再重新读取一遍,用另一种方法来处理数据,最后把两次结果加起来,才得到最终结果。想到这么麻烦,我就感觉一阵绝望——就算我最终写出了程序,我也不敢确保它能正确执行,要调试起来也很麻烦。

到了昨天,我想预期要多次处理数据,不如把这些数据一股脑儿读到内存里去,开始时我觉得这样是一种折衷方法,后来慢慢的发现,这应该是处理问题的正确方法才对。我用两个哈希表,每个元素对应一个列表,来存储从两个视角来分析数据的结果,然后迭代每一个元素对应的列表,进行简单判断,然后就是加法运算计数了,整个解决问题的思路一下子变得如此清晰!

写完了程序之后,我略微反思了一下,其实程序本身没什么复杂的,只是需要把所有的可能情况考虑清楚了,这是最关键的地方。但说来容易,执行起来可不容易。在正常的软件开发中,TDD 是解决这个问题的良药。可我时间紧急,也没有经历来考虑所有可能发生的情况,这其实就给这次开发带来了弯路。另外一个教义,是不要害怕推倒重来。如果我到后来一直坚持一开始的思路,没有变更思路的话,我想就算我最终完成了程序,写的过程应该也非常难受。有趣的是,这样的一个教条,在《人月神话》中已经被提及了。如果正却的开发方法都无法被实行的话,我想最重要的一点,就是要保持冷静,让头脑放空、清晰,是写出正确代码的不二法门。

当然,Ruby 这样的快速开发语言帮了我很大的忙。我想,如果让我自己手工写哈希表,我一定不会这么快的找到解决问题;哪怕是 Java 这样的语言,有自己的数据结构库,使用起迭代来那繁琐的步骤,也很容易把我给绕迷糊了。

重拾 Perl

最近,我开始重新学习 Perl,尝试用 Perl 来完成日常的开发程序。

原因是前几天听第 27 期内核恐慌时,主持人提到了 Perl 6。然后吴涛说起 Perl 时,感情很复杂。我当时心想,我对 Perl 的感情也很复杂咯。首先是对今天的程序员来说,Perl 太原始了,与 Python 和 Ruby 等语言相比,更显古老。回想起来,自从我学习了这两种语言后,我就再没有正儿八经用 Perl 写过程序。而我真正有了属于自己的电脑,是在 2007 年,那个时候我正好开始学习 Python,之后就没有碰过 Perl。

而另一方面,Perl 又是我的启蒙导师。具体的科目不好形容,与 UNIX/Linux、开源等世界有关。在接触 Perl 之前,我对编程,还停留在 BASIC 语言、C/C++ 语言、Pascal 语言上面,对于脚本语言,我的理解只是 .bat。在当时的教科书上,获得的结论是编译型语言比解释型语言在执行上各种优秀,解释型语言只有在学习时才有优势。UNIX 世界繁荣的脚本语言与著名的 KISS 原则,我则一概不知。

记得我大概在高中的时候买过一本小册子,第一次让我接触了 Perl。小册子的内容是 FORTRAN、Pascal、C、Perl、PHP 这五种语言的诞生历史,正是我感兴趣的内容。FORTRAN 那一节看的我比较枯燥,Pascal 是参加 OI 的语言,我比较熟悉。C 我虽然没怎么入门,但也接触过,于是就一章一章的看下来了。Perl 的这一章,是 Larry Wall 写的历史,用女孩子的成长周期来形容每一个版本的 Perl,语言相当幽默风趣,浅显易懂,还有 Larry 在设计 Perl 时的心路历程。虽然我还没有读过一行 Perl 程序,但看完了这一章节,我对 Perl 有了极大的好感。我喜欢的,就是这种不羁的风格。务实、能用的思想,再加上一些宅男一样自娱自乐,不管旁人眼光的态度,让我十分痴迷。

后来,我在新华书店买到了一本《Perl 语言入门》,一本薄薄的小册子。虽说《Perl 编程语言》才是真正权威的教材,但我还是抱着试试水的想法,买了更薄、也更便宜的“小骆驼书”。事实证明,这对我来说是一个极端正确的选择——这本书实在是太棒了!哪怕到了十多年后的今天,我还是认为这本书是编程语言教材中的 No. 1!或许是这本书的作者们都是常年培训 Perl 的老师,他们讲起 Perl 来头头是道、语言风趣、深入浅出。虽然我在阅读的时候,手边没有一台电脑给我来实践,但随着阅读和书中的示例,我很容易的就理解了书中的内容。书中用虽然没有涵盖 Perl 的方方面面,但其中 Perl 的 20% 的内容,就可以解决 80% 的问题。同时,书本的内容引起了我的一些思考,以及计算机世界眼界的变化,带给我的影响是巨大的。

歧路?

昨天要写一个简单的 Ruby 小程序,来快速的对一些数据做出统计。之前用的 Atom 来写的 Java 程序,缩紧方面的设置还需要重新调整。我觉得有些烦了,就干脆关了,用 Emacs 来写。

我的电脑上一直装着 Emacs,结果不成想,可能是因为近期升级了操作系统版本的缘故,在 Emacs 里的汉字字体都变成了隶书,看起来太别扭了。我于是赶紧搜索字体设定办法,结果要编辑 elisp 了,却发现我竟然需要从 org-mode 的文档里进行调整。后来,我想上 USENET 上看看,发现 Gnus 的设定也没了,再想重新设定,却发现也不算容易。最终,我还是解决了问题,但却让我觉得,之前的一些 fancy 的东西,也许对我来说是一种歧途?

之前我用了 Mac OS X 后,同时也渐渐的从每天写程序的日子里退了下来,渐渐的觉得既然用了 Mac 系统,那再用 Emacs 也许有点不合时宜——毕竟从界面、快捷键上,都与 Mac 系统不大一致。而且,我又看了一些关于 Sublime Text、特别是 Atom 等编辑器的文章,觉得也想试试这些东西,于是在一段时间里,我有意的使用这些编辑器来工作,包括编辑文档还有写程序。

但是,我渐渐的发现,我也许已经过了可以随便学习一个新的编辑器的阶段。没有了学习一个新的编辑器的热情。想起在高中阶段,我对 Emacs 的痴迷劲儿,常常读相关的文章,对着其中的配置来弄自己的 .emacs 文件,每知道了一个新的功能,我就可以兴奋好几天。从那个时候,我一直把 Emacs 当做自己的首要编辑器。这也让我放弃了学习其它编辑器的机会,比如 Vim,我虽然会用,但没法把它用好,真让我用它来写代码,我也真做不到。所以,其它的编辑器,我都只是停留在试试而已。

刚开始是 SublimeText,很多人把它捧得很高,因为它是用 Python 写的,Python 程序员可以自己来扩展。它也同样有一个扩展机制来扩充功能。后来有文章又把 Atom 捧上了天,说是很了不起的创意,用了 web 技术来写编辑器。等我用了下来,我发现除了是用 web 技术来渲染文档之外,其它的跟 Emacs 的差别,从思想上来说,不算太大。不同的是 Emacs 使用 ELisp 语言来扩展功能,而 Atom 用了 Nodejs。不过我想既然 Nodejs 这些年来大火了一把,我跟着这个潮流来学习一二,也挺不错。后来终究因为时间忙、注意力差而没有坚持下来,反而让我更加的思念 Emacs 了。

Java and Ruby

我的日常工作之一是统计非法走私信息,在国家级的行业信息系统上有一些数据,但不是我们要的格式。我们要把每个走私案件统计下来,包括走私的产品、数量、案值金额、还有涉及到哪个下属单位等信息。过去用眼镜跟手再加上 Excel 来整理实在是太麻烦了,于是我就写了一个 Ruby 程序,把导出的数据整理成我们需要的格式,输出成 HTML,大大减轻了工作量。

不过这个程序是在我的 MacBook Pro 上写的,而我们的信息系统只有内网能访问。每次使用的时候我只好导出数据,转换成 CSV 格式,然后用电子邮件发给自己,从 MacBook Pro 上收取邮件,转换编码,转换成 UNIX 格式,然后再运行程序,把生成的 HTML 页面再通过电子邮件来发回去,再进行整理。这样一来很繁琐,而来这样只有我自己才能干这件事,我休假时也没法委托别人去做。

所以前几天我考虑了一些比较适合在 Windows 上使用的编程语言,把我的 Ruby 程序移植过去。最后我选择了 Java,因为它比较容易在 Windows 上安装,而且我之前上学时还做过两个 GUI 程序,我也希望把程序做的友好一点,可以推荐给同事用。

我没有进行别的什么设计,只是简单粗暴的对照着之前的 Ruby 程序,逐行翻译过来。断断续续的调试了两天,目前弄了个大差不差的版本,只是这次我的输入输出直接是 Excel 文件,省下了转换格式、编码的步骤。我对于操作 Excel 还没有了解多少,所以还有些合并单元格、修改字体、宽度高度什么的需要加上,其它数据方面今天总算是调试成功了。

谈谈使用 Java 的感想。

我在 2010 年的时候写过一篇文章,记载着是一次用 Java 语言完成作业的经验,我那时候花了一夜完成了那一周的作业,实现了几个数据结构并且排序。那时候我用 Java 还比较熟练,有些东西不需要像现在一样查文档,结果没怎么调试居然成功了,让我对 Java 好感大增。不过这次跟 Ruby 比起来,Java 就显得太繁琐了。

过去我对 Java 的一些比较“高级”的用法不大了解,因此一些迭代器呀什么的也用的不多。这次因为在 Ruby 程序里用了很多迭代,感觉比自己苦兮兮的写数组来说方便太多了,因此就用了不少的迭代,结果每次新建一个迭代器实例,再用 hasNext()next() 函数来遍历,比起 Ruby 的一个 each 就搞定实在是繁琐。这样的另一个后果就是多了一堆代码,我在 NetBeans 里面看的眼都乱了,调试的时候直接找不到头绪。最终搞定了我是觉得没问题的,但是搞定前费的功夫实在是大。所以近年来,要完成一些任务,我绝对是偏爱脚本语言。

写到这里,不禁感叹,如果我们公司用的是 UNIX 操作系统该有多好,可惜绝对不现实呀。

过去对这方面的感触不深,但通过对比就觉得 UNIX 的编程方式实在是太方便太先进了,比起 Windows 的模模糊糊好了不知道多少倍。可惜 Ruby 在 Windows 下执行不大方便,做成可执行的 EXE 就更不容易了,简直没有头绪。

计划重新配置 Emacs

Emacs 是我最喜欢用的编辑器。最早我是在大约 2005 年从王垠的网站上知道它的,同时听说的还有 VIM,后来经过尝试,我觉得 Emacs 更加符合我的口味,用起来更为自然,因此从很早起我就用 Emacs 来写程序。

我最早的 .emacs 配置文件的内容也是从王垠的文章中获得的,王垠为此写过两篇文章,一篇是基础的配置,另一篇是讲各种好用的 Elisp 包,我从两篇文章中选取了我需要的内容,放进了我自己的配置文件中。这个配置文件我用的非常久,中间也经历了我从 Windows 到 Linux 到 Mac OS X 这个操作系统替换的过程。

后来我得知了有 Emacs Starter Kit 这么一个 Emacs 配置的项目后,立马对其动心了。主要原因是它使用 Org Babel 来把配置文件写成了 Literate Programming 的形式,可以在配置文件中大段的写入对于某一部分代码的想法,而 Org Babel 会在启动时自动提取出所有配置的代码,非常方便。Starter Kit 还有一个好处,就是它把很多相关的配置提取出来,放进了不同的文件中。我过去的 .emacs 是一个大文件,所有的东西都在里面。Starter Kit 则不是,它给了很多模块,需要的时候可以调用。这样的配置文件更加的清晰了。

不过 Starter Kit 也有让我不满意的地方。首先它对我来说有点大,很多配置在我看来有些过了,反而让我一下子有点措手不及。在我看来 Emacs 主要还是一款编辑器,写项目的时候可以有些项目管理的功能,但并不意味着它就要做一个 IDE。我更喜欢比较简单的东西,够用即可,过犹不及。另外就是它的效率问题,它让我的 Emacs 启动速度减慢了许多,今天我又往里面加入了一些 Ruby 相关的配置,速度又一次变慢了。今天我也看到了这篇文章,讲优化 Emacs 配置的,对我很有启发,里面很多的东西在我的配置文件中还没有被用上,于是我计划要整理一下这些配置。

我开始的想法是采用 Starter Kit 的思想,但不要直接用它的代码。首先我很喜欢文学编程,尤其是对于 Emacs Lisp 这种我不能完全掌控的语言来说,有了相关的文字解释可以省去我很大的功夫。另外,这样做的好处是我可以真正的掌控 Emacs 的配置,目前 Starter Kit 中又好多代码我不知道是做什么用的,但又不敢胡乱修改,只好让它们运行。这次借着重写的机会要好好筛选了解以下。

不过 Starter Kit 有一些好的设计,我还没有把握能自己实现出来。比如说它对于第三方插件的管理,我还需要看一下它的代码。另外,Starter Kit 自己也在演进中,我自己配置就意味着要与 Starter Kit 社区断裂,不知道是好是坏。总之目前我有这个想法,但是否能实现出来,我还有些惴惴。

服务器的文件不知不觉的被人动了

今天早上偶尔访问我的服务器上的文件时,发现当我访问一个 HTML 文件 时,Chrome 浏览器提醒我这个页面有不良程序。

Chrome 浏览器发出的警告

Chrome 浏览器发出的警告

我第一个反应是“怎么可能”,这明明是我自己的服务器,文件也是我几年前自己编辑放上去的,有了木马我自己怎么可能不知道。不过为了以防万一,我用 SSH 登陆了服务器检查了一下,没想到这个文件里确实有不明脚本。

不良脚本的内容截图

不良脚本的内容截图

这个文件很老旧了,早在我还在用 Dreamhost 共享空间的时候就已经存在了。中间我的帐号也被黑过,因此有些文件被加了木马也是有可能的。这次这个脚本是用 JavaScript 写的,放在了 的后面,用 DOM 语法在页面里插入一些内容。具体作用是什么我不清楚,因为脚本里加了一些乱码来变换真实内容,我也没有兴趣去仔细研究它。

我检查了一下其它文件,发现没有问题。

升级了 tweets-page

前几天偶尔上 Twitter 的时候看到别人的一条推,说是 Twitter 可以导出自己过去发布的所有消息了。这是我一直想做的,原因之一是 Twitter 自己限制了它是一个快速更新的消息发布集中地,而已经发布了的消息就不是它所关注的了。所以过去你要是在 Twitter 页面上不断的点“上一页”,能看到的页面是有效的,印象里好像回退到 20 几页就不能再往前看了,不知道现在有没有改进。因此我很早之前就有把我所有的 Twitter 条目都导出来的想法,可惜 Twitter 的 API 也有类似的限制,因此这个想法一直没有实现。

第二个原因是让我在国内的父母可以看到我的推。由于我经常发推,因此从我的 Twitter 记录中可以看到我的生活。这样我父母能更放心一些。

我写 tweets-page 是从 2009 年 7 月开始的。那个时候我刚刚回国,Twitter 已经被封锁了。当时我和家人在北京的饭店住着,父母正好有假期,准备带我在北京转转,看看鸟巢等新建设的地方。我因为时差关系到凌晨三点多就睡不着了。自己住在一间客房里没事干,又不想看电视,于是就想解决从国内上 Twitter 的问题。一开始时我用 ssh -D 给自己开个通道用,一会后嫌麻烦,因为代理的速度不高,一些国内的页面用代理会更慢,而且每次开代理还麻烦(那时我还不会 screen)。所以我就自己写了一个程序,让我可以浏览 Twitter 并发布新推。当时的代码怎么写的我早就忘了,好像也没有备份。浏览了一下当时的推特记录,说是用的 Perl 调用 curl 来用官方的 API 来更新,印象里时一个 CGI 小程序,非常简陋,还有不少的问题,当时仅仅是临时用用。

然后回加拿大后,我用 Ruby 写了一个小程序,通过 twitter4r 来获取我的 tweets,保存在数据库中,然后用程序生成页面浏览。API 在那时已经不支持 since 参数了,我只能从某个时间段开始抓取,之前的内容就只好放弃。程序最终写成了,不过我当时对服务器的知识太少,用的还是 Dreamhost 共享主机,最终用 Crontab 让程序定时运行的时候,发现无论怎么样都找不到我用 gem 安装的 twitter4r。如果程序不能定时运行,我每天要登陆到主机上手动执行一遍程序?非常不现实。所以最后我只好放弃,最后的生成结果部分我也懒得弄了。

印象里之后还试过几次,好像都没有成功。

到了 2012 年 5 月,我重新写了一次,结果弄成了。这次用了 Twitter 库和 Sequel,在服务器上我也不再用 SQLite 了,而是用 MySQL。除了保存到数据库之外,它还能在刷新后立即生成输出页面。输出的页面是一个比较大的 HTML 静态文件,我曾经想写一个分页功能的,后来一直没有兴趣碰它。在解决了 Crontab 的问题后,它就一直在我的服务器上工作着,一直到了现在。

生成 Twitter 静态网页

我从 2009 年就想写一个程序,把我的 Twitter 记录生成为静态的网页,放在我的服务器上,可以让墙内的人浏览。这样,在国内的父母也可以像 Twitter 被封锁前那样通过我的 Twitter 来了解我的生活情况。

当时我完成了一个小程序,但仅仅是做实验用的,有相当多的小问题。当时用的是 twitter4r 库,很多东西都不大成熟,用它写程序挺麻烦的。当时也遇到了各种问题,都在上面的文章中描述过。后来的代码总结在这篇文章里

最近我看了一些关于 Rails 的文档,写了一些程序,受到了一些启发,于是觉得可以重新写一写这个程序了。现在很多东西也变了,有了 twitter 库,获得记录的方法也更方便了。我如今也不再执着于把所有的 tweets 都保存下来了。另外,我对于数据库方面的了解更多,所以没有干巴巴的用 sqlite 接口来写 SQL,而是用了 Sequel 库,在本地用 Sqlite 3 调试,在服务器上就用 MySQL。结果程序很快就出来了,在纸上做设计,把要做的步骤考虑清楚了之后,很容易的就完成了代码。当中遇到的困难之一是对 Ruby 的不熟悉,很多东西我都需要查找例子,这是练习不足的原因。困难之二就是在 Sequel 的文档搜索信息费了我很多功夫。很多东西都不能想当然,我需要摸索着试验。比如说查看一条 tweet 是不是已经在数据库中有了,只要找找有没有相同的 id 就可以了,这个操作就让我费了很长时间来试验才知道正确的用法。

我过去从来没有写过 MySQL 程序的经验,因此在服务器方面也遇到了问题。首先是 MySQL 本身的启动问题,这个放在下一篇文章中专门谈,其次是安装 mysql 的 gem 时的问题,系统在哦年时提示:

*** extconf.rb failed ***

Could not create Makefile due to some reason, probably lack of

necessary libraries and/or headers.  Check the mkmf.log file for more

details.  You may need configuration options.

只是说缺少依赖,但并没有说具体少什么。后来我找到这篇文章,知道了原因,安装了 libmysql-ruby 和 libmysqlclient-dev 库之后就没问题了。

OS X 10.6 的 AppleScript 中文 bug

前几天一个偶然的机会我发现了 Shawn Blanc 的 blog。这个 blog 包含了一些时尚科技的评论,更新速度比较高。作者 Shawn Blanc 目前是专职维护这个 blog,blog 本身有收费会员订阅的项目,每月花 3 美元就可以阅读一些更多的内容。但免费的内容已经非常丰富了,作者有这个底气征收付款,在中文 blog 圈子中应该是比较难以想象的吧。

我从这个 blog 中看到一篇 MarsEdit 的评论,因为我自己也在用 MarsEdit,它是我的计算机上的几个花钱购买的商业软件之一,于是我就花了点之间仔细看了一下作者的评论,从中知道了我之前一直以为不存在的字数统计功能,竟然在脚本菜单下面。我知道自己还不是一个比较资深的 Mac 用户,比如像mac script menu 这样的菜单我从来没有点过。这次知道在 MarsEdit 这个菜单下面,就有对文章的统计功能。于是我点了统计功能后,MarsEdit 的 CPU 占用率马上飙倒了 99%。最后只能把这个进程给杀掉。杀死进程后 MarsEdit 有崩溃报告功能,我就顺便把这个 bug 给报告了。

Apple 本身也有这种功能,不过可能用户量太大,Apple 应该只把它当作一个记录统计的作用。而 MarsEdit 的开发公司 Red Sweater 这种规模不大的公司,收到这种报告的次数可能不多吧,反正我第二天就收到了 Red Sweater 的回信,请我帮助他们 debug。我把造成问题的那篇文章发送了过去,因为我的文章是中文的,我以为 MarsEdit 可能对多语言支持的不够完善,就提了一句是不是 Unicode 方面的问题。

之后对方发来邮件,包含了一个另一个版本的字数统计脚本的附件,让我用这个脚本来试试。我试了一下,仍然有问题。脚本是用 AppleScript 写的,我从来没有学过这门语言,但据说它非常简单,脚本本身也不长,我看了几眼就大体上知道是怎么回事了。稍微研究一下,我想找出来是我的文章的哪个部分让这个程序的哪一行卡住了。于是排除了一下,发现造成问题的原因比较古怪,也不是所有中文都通不过,我发现的一种情况是只有字符串中包含一个汉字,跟上一个空格,再加上一个数字的时候,words of inputString 就会卡住。inputString 就是输入的字符串,脚本中用了 number of words of inputString 来获得字符串中包含的字符或汉字。我的那篇文章中正好有这种情况。实际上,我从几年前写文章就习惯再汉字跟数字及英文字母之间加上空格,这样更清晰一些,所以我的 blog 中一定会出现很多这种情况,我的大部分的文章都没办法用这种办法来统计字数。

我把我的发现发给了 Red Sweater,对方回信告诉我说这个问题在 OS X Lion 中不存在,因此似乎是 Mac 系统本身的问题。出问题的代码仅仅是调用了系统给的函数,因此也不好解决。对方说他们会想别的办法来获得字数统计功能。