StarDict词典转sqlite DB(StarDict文件格式)
2012-11-14 18:52:00在网上找了一圈没有看到好点的开源词典库
唯一丰富一点的是StarDict,只可惜因为版权问题,已经从SourceForge移除了,好在词典还留下来许多
一般下载的词典是一个压缩包*.tar.bz2,解压之后是三个文件:*.ifo *.idx *.dict.dz
其中的*.dict.dz还需用7Zip解压一次 当然rar也可以
于是得到了三个词典文件:*.dict *.ifo *.idx
首先这些文件除了*.ifo都是以二进制保存的
一个个解释一下文件的作用和格式:
- *.ifo
这个文件中包含了辞典信息
包括版本,创建时间,来源,等等。可以直接用文本编辑器打开。在解码中无用。
- *.idx
辞典的索引文件,查找单词的时候遍历这个文件就可以找到解释在*.dict的什么地方,格式要求如下:
上图说明了*.idx
的格式,它是又很多单词连接构成,每个单词又由三部分组成
首先是单词本身,是一个C String,由\0
结尾
然后是该单词的解释在*.dict
文件中的偏移量,是unsigned int
最后是该单词解释在*.dict
文件中的长度,也是unsigned int
- *.dict
有了*.idx
文件,其实*.dict
文件的格式就没有那么严格了,其实制作dict时只要一段段往里面塞解释,然后记录下offset(偏移量)和length(长度)记录到*.idx
中就行了,当我们要取出解释的时候,只需根据偏移量和长度,用fseek
,fread
很简单就能得到。
原理有了,能得到数据了,接下来写入sqlite db就很简单了,我直接贴上代码,有错误处,还望原谅以及及时指出
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sqlite3.h>
char ifo[1024] = "langdao-ec-gb.ifo";
char idx[1024] = "langdao-ec-gb.idx";
char dict[1024] = "langdao-ec-gb.dict";
sqlite3 *conn = NULL;
int i;
int toupper(int c);
int getsize(FILE *fp)
{
int current = ftell(fp);
fseek(fp, 0, SEEK_END);
int size = ftell(fp);
fseek(fp, current, SEEK_SET);
return size;
}
int getvalue(FILE *fp, int offset, int length, char *buf)
{
fseek(fp, offset, SEEK_SET);
fread(buf, length, 1, fp);
buf[length] = 0;
return 0;
}
int open_db()
{
if (SQLITE_OK != sqlite3_open("output.db", &conn))
{
printf("can't open the database.");
exit(-1);
}
return 0;
}
int close_db()
{
if (SQLITE_OK != sqlite3_close(conn))
{
printf("can't close the database: %s/n", sqlite3_errmsg(conn));
exit(-1);
}
return 0;
}
int insert_word(const char* word, const char* value)
{
static int flag[26];
static int fflag = 1;
char sql[5000] = {0};
char *err_msg = NULL;
if (fflag)
{
for (i = 0; i < 26; ++i)
{
flag[i] = 0;
}
fflag = 0;
}
char table_name = toupper(word[0]);
int flag_idx = table_name - 65;
char explain[4096] = {0};
char real_word[512] = {0};
for (i = 0; i < 4096; ++i)
{
if (value[i] == '"')
explain[i] = 39;
else
explain[i] = value[i];
if (value[i] == 0)
{
explain[i] = 0;
break;
}
}
for (i = 0; i < 512; ++i)
{
if (word[i] == '"')
real_word[i] = 39;
else
real_word[i] = word[i];
if (word[i] == 0)
{
real_word[i] = 0;
break;
}
}
if (flag[flag_idx] == 0)
{
sprintf(sql, "CREATE TABLE IF NOT EXISTS %c (id integer primary key autoincrement, word varchar(512), explain varchar(4096))", table_name);
printf("%s\n", sql);
if (SQLITE_OK != sqlite3_exec(conn, sql, 0, 0, &err_msg))
{
printf("operate failed: %s\n", err_msg);
exit(-1);
}
flag[flag_idx] = 1;
sql[0] = 0;
err_msg = NULL;
}
sprintf(sql, "insert into %c ( word , explain ) values (\"%s\", \"%s\")", table_name, real_word, explain);
//printf("%s\n", sql);
if (SQLITE_OK != sqlite3_exec(conn, sql, 0, 0, &err_msg))
{
printf("operate failed: %s\n", err_msg);
exit(-1);
}
return 0;
}
int main(int argc, char *argv[])
{
// open idx file
FILE *fp_idx = fopen(idx, "rb");
int size_idx = getsize(fp_idx);
// open dict file
FILE *fp_dict = fopen(dict, "rb");
open_db();
// set counter
int cnt = 1;
// pull out each word from idx
char name[512];
char value[4096];
unsigned int offset;
unsigned int length;
int name_ix = 0;
char c = 0;
while (ftell(fp_idx) != size_idx && cnt < 435468) {
fread(&c, 1, 1, fp_idx);
if (c != 0) {
name[name_ix++] = c;
} else {
// null-end name
name[name_ix] = 0;
// get offset and length
fread(&offset, sizeof(offset), 1, fp_idx);
fread(&length, sizeof(length), 1, fp_idx);
// correct byte order
offset = htonl(offset);
length = htonl(length);
// get value
getvalue(fp_dict, offset, length, value);
// output result
insert_word(name,value);
// re-initialize
bzero(name, sizeof(name));
name_ix = 0;
cnt++;
}
}
close_db();
fclose(fp_idx);
fclose(fp_dict);
return 0;
}