英汉字典架构设计

一、数据文件

字典数据文件有两个:DictSpch.bin和DictSnd.bin

英汉字典架构设计

(文件名有点混,太相近了,不易区分具体内容。因为最初我们 V1版本字典只有词头和解释,当时就一个文件,名叫Dict.bin;后来V2版要加发音功能 ,文件名改为DictSpch.bin,结果又发现声音数据太大,在sd文件系统中放不下,声音数据又被单独抽出来放到隐藏盘,名叫DictSnd.bin)

  1. DictSpch.bin,字典数据(词头、词义)部份,是必须的,缺少的话,字典没法运行;

  2. DictSnd.bin,声音数据部份,可选,缺少的话,只是无发声,但字典可正常查阅词义;

  3. DictSpch.bin和DictSnd.bin必须配套使用,即它们ID必须相同,否则不会发声;

二、声音数据的结构

英汉字典架构设计
声音数据,即DictSnd.bin文件中存储的数据

1.数据标识ID

ID区域是为了与词头数据相匹配而加的数据区域,避免不同版本的词头与发声的混用造成错误而加入的。

ID区的数据结构:

英汉字典架构设计

实例

英汉字典架构设计

2.wav 参数

wav参数包括:通道数、采样率、采样宽度,这是发声函数需要的重要参数。所有词头使用相同参数。

wav参数结构

英汉字典架构设计

实例

英汉字典架构设计

可以看出:
通道数:0x0001,即1个通道(单通道)
采样率:0x3E80 =
16000,即16K
采样宽度:0x0020,2字节,即16bit

3.发声数据

发声数据结构很简单,就是各个单词的wav声音数据,一个一个的顺序排列。

单条数据结构

英汉字典架构设计

实例

英汉字典架构设计

长度:0x00004B1A
= 19226,即从0x10开始,19226字节的数据都是同一个单词的声音数据。

在词头的信息(DictSpch.bin)中,会保存该词头对应声音数据的偏移地址,如0x12,则可跳到DictSnd.bin的0x12处,先读4字节,计算出数据长度,然后再读长度个字节声音数据,则完成发声数据的查找。

三、字典数据结构

字典数据结构是最复杂的部分,该部分的设计影响着字典的数据大小与样机中字典搜索的速度

英汉字典架构设计

1.数据标识ID

该id的结构与作用与声音数据中的ID是一样的,用于两者的匹配。详情请参考声音数据结构中的介绍

2.头部信息

头部打桩词条总数及各部分数据的起始位置信息

头部数据结构是
英汉字典架构设计
实例

英汉字典架构设计

词条总数:0x0000B51E,说明有46366个单词;
索引表偏移:0x00000016,即索引表的数据开始于0x16处;
词头偏移:0x0001F6D8,即词头数据开始于0x1F6D8处;
解释偏移:0x00113E30,即解释数据开始于0x113E30处;

3.关键字索引表

索引表用于快速定位我拉的搜索结果。对于用户的输入,我们不是直接去比较单词,面是先在索引表中搜索,快速定位我们输入的查找关键字所指向的单词的位置。

关键字索引表的结构

这里比较难以理解,是字典的核心部分。必须理解我们单词排序的方法,索引表的构成,索引表在数据文件中的存储结构,才能明白字典的查找方法。

英汉字典架构设计

a.索引节点信息

英汉字典架构设计
这个图表,是逻辑上的理解,对于具体的实现,可以看下面的索引表的存储格式

b.索引节点说明

  1. 每个节点记录了当输入本节点字符时,在字典中能探索到的单词范围。如输入‘a’,那第0-9个词头都符合条件;
  2. 节点的儿子列表,表示还可继续输入的字符序列,如’a’的儿子列表’bmn’,说明还可继续输入b,m,n,因为有以’ab’,‘am’,'an’开关的单词
  3. 在字典中,一共定义 了9个层级的索引节点。层级太多,索引表会更大;层级太少,搜索速度又太慢
  4. 当某级包含的单词范围少于或等于16个时,不再记录它的儿子节点,本级内采用二分法查找(文档图例中是2个)
  5. 图例搜索过程:
    当输入“a”时,第0~9(共10条)都匹配;
    继续输入“m”,发现“a”的二儿子是“m”,跳到“m”节点,第3~5条匹配;
    再输入“a”,发现“m”的唯一儿子是“a”,跳到“a”节点,第4~5条匹配;
    再输入“s”,由于“a”结点没有儿子,则二分法在“a”节点查找,第4条匹配;

c.索引表的存储格式

英汉字典架构设计

  1. 先存一级索引,再存二,三…九级索引索引
  2. 一级索引即26个英文字母,所以一级索引有26个节点
  3. 二级及二级以后的索引块即上一级的儿子索引,个数由具体电子字典的词条数决定
  4. 一级索引的存储格式与其他级的不同

d.一级索引存储格式

节点存储格式:
英汉字典架构设计
实例:
英汉字典架构设计

  1. 每个节点8个字节,一级索引区共占用8X26 = 208字节;
  2. 字母ch节点地址的计算方式是:(ch - ''a)X 8
  3. ‘a’ 字母节点地址是0。可以看出,以’a’字母开关的单词,第一个序号是0x0000,即第0个,最后一个序号是0x0982,即第2434个,儿子节点的起始地址是0x000000D0;
  4. 后面任意字符如‘x’的节点地址是:(‘x’ - ‘a’)X 8 ,这样即可得到‘x’区配单词的序号范围和儿子节点的范围
  5. 如果某节点的偏移为-1(0xFFFFFFFF),说明没有儿子(一级索引都有儿子,不会出现偏移为-1的情况)

e.二级索引存储格式

英汉字典架构设计
英汉字典架构设计

  1. chid_num:一个字节,表示儿子数量,如0x1A,即有26个儿子;
  2. chid_list:儿子列表,child_num 儿子全列在这里,如’abcdefghijklmnopqrstuvwxyz’;
  3. child_info:每个儿子的信息,按顺序排列,结构与一级索引一样;

f.实例-搜索过程

假如输入’ahead’,搜索过程如下:

  1. 输入’a’时,定位到一级索引’a’的信息,可得到此时的搜索结果是第0条到第2434条,即字典中的第0条到第2434条都是以’a’开关的单词;
    英汉字典架构设计
  2. 再输入‘h’。由一级索引‘a’的儿子偏移不为-1可得知,她有儿子,所以要先确定是否有’h’的儿子;
  3. 跑到0x000000D0的位置,读出‘a’的儿子数量,为0x1A(26),然后继续读26个字符;
    英汉字典架构设计
  4. 在儿子列表中查到’h’是第7个儿子,定位到’h’节点的位置,则得到搜索结果是:字典中的702-709条以’ah’开头;
  5. 继续输入‘e’,由于二级索引’h’没有了儿子,则不能继续在索引表中查找了,此时要切换为二分法查找,即在’h’的范围(702-709)中查找,在我们的字典中,就只有一条符合记录,即705条’ahead’符合;
  6. 如果还要输入,那就需要比较是否与ahead匹配就行了。

4.词头数据

词头就是字典中的单词,字典中的所有单词都是按字母顺序排列存储在这里。词头的排序方法是:单词中只有字母参与排序,数据与其他字符对排序无影响;字母不区分大小排序,只有两者相等时再区分大小写比较,如:
A
a
B
b
C
c

词头数据结构

英汉字典架构设计
词头数据分两部份:地址部份和词头部份

地址部分

址址部份是定义每个单词存储位置的散列地址,包括:词头地址、词义地址、发声地址

英汉字典架构设计

英汉字典架构设计

  1. 第n个单词地址的散列函数是:H(n) = 12n
  2. 从起始地址读12字节,即可确定第n个单词的词头存储位置,词义存储位置,解释存储位置
  3. 词头和词义是一定存在的;
  4. 发声部分可不存在,若发声数据的位置为0xFFFFFFFF,则说明无声音数据;
  5. 注意:词义地址是该单词的结束地址,即下一个单词的起始地址。而第0个单词的起始地址就是0地址处;

词头部分

词头部份是所有单词散列存储的地方,每个单词的散列地址存储于地址部份
英汉字典架构设计
英汉字典架构设计
从地址部分可看出,第一个单词’A-1’存储在0x00087D68处,跳到该地址处,可看出与实际相符。
后面都是按顺序一个接一个存储的。词头按ascii码存储。

5.词义数据

词义数据就是对应单词的解释部分,顺序与词头一一对应。

词义数据结构

英汉字典架构设计

存储方法

存储方法简单,就是按词头顺序逐个存储。词义部份是unicode编码的。

寻址方法

(1)
第1个单词的起始地址offset1=0x00000000,由第1个单词的词头地址部份可获取结束地址offset2,则其长度为 len = offset2 – offset1;

(2)
第n个单词的起始地址offset1从第n-1个单词的词头地址部份读出,其结束地址offset2由第n个单词的词头地址部份读出,其长度为 len = offset2 – offset1;

词义实例

英汉字典架构设计