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都是以二进制保存的

一个个解释一下文件的作用和格式:

  1. *.ifo

这个文件中包含了辞典信息

包括版本,创建时间,来源,等等。可以直接用文本编辑器打开。在解码中无用。

  1. *.idx

辞典的索引文件,查找单词的时候遍历这个文件就可以找到解释在*.dict的什么地方,格式要求如下:

image

image

上图说明了*.idx的格式,它是又很多单词连接构成,每个单词又由三部分组成

首先是单词本身,是一个C String,由\0结尾

然后是该单词的解释在*.dict文件中的偏移量,是unsigned int

最后是该单词解释在*.dict文件中的长度,也是unsigned int

  1. *.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;  
    }