此文章已过期,点此查看sydict最新版本的介绍
寒假在家真是有够无聊的,不能上网,没交通工具可以离开家里。
于是乎,把从学校里面带过来的几本书给看了。
之后又没东西看了,就一直在看Emacs Info。看着看着发现好多英文单词都不认识,都怪当初没有把英语好好学。这样,我就想到了Linux下的有名的国产开源辞典(stardict)。但是呢,每次都在emacs和stardict当中切换好不舒服。所以呢,我就打算自己写个在Emacs里面查询单词的接口来调用stardict中已经整理好的字典文件。就这样,sydict就这样产生了。
花了几个小时研究了剑桥高级英语的字典文件夹,里面有四个文件。一个dict,一个idx,一个info,还有一个不知道干什么的,不过这与我无关,不是
么?经过查看后发现dict文件保存的是单词的解释,是完全把所有的解释杂糅在一起的那种。idx文件是一个目录文件,保存着每个英文单词对应在dict
文件中的位置的信息。而info文件则最简单,是关于这本字典本身的信息,比如字典名称呀,作者呀,创建时间呀什么的,我这里就不需要了。所以,我这次使
用的其实就两个文件,idx文件和dict文件。具体思路就是首先在idx文件中查询具体单词是否存在,以及它的解释在dict中的位置,然后在dict
中找到相应的位置进行输出。
有朋友可能就会说了,stardict既然是开源软件,为什么还要费力去研究它的字典文件的格式呢?我想说的是:首先,我在家里是不能够上网的,自 然获取不得它的源代码。其二,看源代码和直接研究它的文件格式都是学习的一种方式,我只是选择其一而已。那么先让我们看一下idx文件的具体内容吧,首先 是od -c的部分输出:
下面是od -x的输出:
对照后再联系“idx”这个名字很容易联想到这个文件的具体格式:单词+位置(8个字节)。那么这8个字节又是如何保存位置的呢?仔细观察能够发 现,这8个字节应该是分成两部分的,第一部分的四个字节(对应一个int)是起始位置,后面的四个字节是对应的单词的解释的长度。而单词与位置用一个空字 符(’\0′)来分隔。这样,我很容易写出读取该文件内容的c语言实现。
while ((c = fgetc(fp)) != EOF) { if (c != 0) /* 单词字符 */ else /* 读取2个int,分别是起始位置和解释长度 */ }
本来故事到这里也就结束了,可是输出后居然发现这两个整型的输出很有问题。原来是系统在解释整型的时候出现了问题,可能是该文件是在window下生成的 吧,而我却在linux下读取信息。所以需要用htonl来对两个int进行转换。再次编译执行,输出就正常了。打开dict文件,fseek到指定位 置,读取一定长度字符。果然输出就是我们所需要的该单词的解释。
本以为到这里问题都差不多了,可是还有一些细节上还不知道怎么处理。比如:index的信息是保存在内存里面还是每次查询单词都解析下一遍文件呢?
这方面,我选择了前者,现在的内存如此廉价,也不差那几百kb的占有率。于是我重新写了idx文件的解析程序,生成一个Elisp的脚本。然后让
Emacs解释执行,也就在Emacs里面保存了这个信息了。那么之后要查询单词的话就不用涉及这个idx文件了。我又用c语言写了一个读取指定文件的指
定位置内容的程序,取名sydict。(其实这个才是主要的输出程序)
比如输入 sydict ./oald.dict 1234 64
那么就是输出oald.dict文件从1234到1234+64位置处的内容。之所以不用Elisp完成是考虑到效率的问题,因为oald.dict文件有10M+,并不用完全读取全部的内容。每次查询其实也就读取几百个字节罢了。
之后就是Emacs接口的设计了,我简单的调用上面的那条shell来输出内容。
(setq sydict-prog-name “sydict”) (setq sydict-dict-path “/etc/sydict/oald.dict”) (defun sydict-look-up-word (word) (interactive “sword: “) (let ((index (nth (position-if (lambda (aitem) (equal word (car aitem))) sydict-alist) sydict-alist))) (shell-command (format “sydict /etc/sydict/oald.dict %d %d” (nth 1 index) (nth 2 index))) (save-excursion (set-buffer “*Shell Command Output*”) (goto-char (point-min)) (insert (format “%s ” word)))))
这样就完成根据oald.dict文件来查询具体单词的目的了。
具体使用步骤:
1.把sydict可执行文件放到PATH中存在的文件夹中。
2.把oald.dict的位置赋值给sydict-dict-path变量。
3.将sydict.el文件放到你的load-path中的某个文件夹中。
4.在你的.emacs文件夹中加入这句:
(load “sydict”)
5.你可以使用C-xC-e执行上面那句话,也可以重启Emacs来载入sydict。
这样,你就可以使用sydict-look-up-word命令来查询单词了。
今天sourceforge不知道为什么登录不上了,所以就用M$的skydrive上传源码了。