山寨格式,欢迎大家提提意见。

查询库:dic_rust.zip (40.0 KB)
写入器:dic_writer.zip (39.9 KB)

文件类型

索引文件(.key)

  • 存储检索用的索引结构
  • 根据需求选择不同的索引类型
  • 指向对应的标题文件

标题文件(.head)

  • 存储词条的标题信息
  • 记录正文位置和锚点
  • 包含去重的字符串表

正文文件(.rsc/.nrsc)

  • 存储实际的HTML内容
  • 按块压缩存储
  • 支持分片

元数据文件(.metadata)

  • 记录所有文件的索引
  • 定义搜索模式
  • 存储词典基本信息

索引类型

1. 词头Trie索引

用于精确的词头查询,比如输入"app"能匹配到"apple"、"application"等。

适用场景: 词典、术语表这类需要前缀匹配的场景

数据结构:

TrieNode {
    children: map<char, TrieNode>    // 子节点映射
    head_ids: list<int>              // 这个节点能匹配到的所有词条ID
    is_end: bool                     // 标记是否为完整词
}

字符映射表把字符映射成连续的ID,节点表记录每个节点的子节点偏移和匹配结果偏移。查询时从根节点开始,逐字符跳转,收集路径上的所有匹配结果。

2. 字符级倒排索引

把文本拆成单个字符建立倒排索引,适合CJK文本的任意子串查询。

适用场景: CJK例句短语搜索?

数据结构:

CharIndex {
    char → list<(entry_id, [positions])>    // 字符到词条+位置列表的映射
}

存储时会根据字符分布密度选择策略:

  • 直接数组:字符范围集中时(密度>30%),用Unicode值直接索引
  • 稀疏数组:字符分散时,存储(unicode, offset)对的排序列表

查询"例句"时,先找到包含"例"的所有词条,再从中筛选出同时包含"句"且位置相邻的结果。

3. 分词级倒排索引

对文本进行分词后建立倒排索引,配合B+树结构支持前缀、后缀、精确匹配。

适用场景: 英文全文检索

数据结构:

InvertedIndex {
    term → list<(doc_id, [positions])>    // 词项到文档+位置列表
}

B+Tree {
    forward_tree   // 正向树:支持前缀查询("app*")
    reverse_tree   // 反向树:支持后缀查询("*ing")
}

B+树的叶节点存实际数据,内部节点存索引。叶节点间通过next指针串联,方便范围查询。

标题文件结构

标题文件是连接索引和正文的桥梁。

文件头:

magic: 0x48454144
version: 1
entry_count: 词条总数
encoding: UTF-16LE
mode_name: 搜索模式名称

索引段: 固定16字节一条,记录(head_id, data_offset)

数据段: 每条记录包含:

head_id       // 词条ID
page_id       // 正文ID
item_id       // 正文内的锚点ID
string_index  // 在字符串表中的索引
content_info  // 正文文件ID、偏移、长度

字符串表: 去重存储所有标题文本

StringTableEntry {
    content_hash   // CRC32校验
    data_offset    // 在字符串数据区的偏移
    data_length    // 长度
    ref_count      // 引用计数
}

正文文件结构

RSC格式(常规正文)

把多条正文打包成块,压缩后存储。

块结构:

[4字节压缩长度][压缩数据]

压缩数据解开后是:

[4字节长度][UTF-16LE文本][4字节长度][UTF-16LE文本]...

映射文件(.map):

MapRecord {
    zoffset   // 压缩块在文件中的位置
    ioffset   // 内容在解压后块内的偏移
    flags
}

索引文件(.idx): 把content_id映射到map_index

块大小默认64KB,文件大小上限10MB后自动分片。

NRSC资源文件(这部分其实还没做好)

用于音频、图片等二进制资源,不分块直接存。

NrscMapRecord {
    fileseq       // 第几个分片文件
    file_offset   // 在分片中的偏移
    length        // 数据长度
    compression   // 压缩标志(0=原始 1=zlib)
}

分片上限50MB,资源单独压缩,压缩率不到90%就不压。

实际用例

假设有这样一段HTML:

<html>
<div id="1">这是例句1</div>
<div id="2">这是例句2</div>
<div id="3">这是例句3</div>
</html>

封装流程:

  1. 整段HTML作为page_id=0存入.rsc
  2. 把三个例句分别提取,建立标题记录:
   head_id:0, page_id:0, item_id:1, headline:"这是例句1"
   head_id:1, page_id:0, item_id:2, headline:"这是例句2"
   head_id:2, page_id:0, item_id:3, headline:"这是例句3"
  1. 对"这是例句1"、“这是例句2”、"这是例句3"建立字符级索引

查询流程:

搜索"这是例句"时:

  1. 字符索引返回三条匹配
  2. 点击"这是例句1"
  3. 根据head_id=0找到标题记录
  4. 获取page_id=0, item_id=1
  5. 从.rsc读取page_id=0的HTML
  6. 定位到<div id="1">锚点
  7. 渲染显示

元数据文件

统一管理所有文件。

搜索模式:

SearchMode {
    mode_name      // 内部标识
    display_name   // 显示名称
    key_file_id    // 索引文件ID
    priority       // 优先级(数字越小越靠前)
}

文件记录:

FileEntry {
    file_id       // 文件ID
    filename      // 文件名
    file_size     // 大小
    file_type     // 类型(KEY/HEAD/CONTENT)
    shard_index   // 分片序号
}

元数据里不直接存文件路径,用file_id关联。查询时先读元数据,拿到file_id,再去对应文件里读数据。

文件ID规则

  • 1-99:索引和标题文件
  • 100+:正文文件
    • 100: .idx
    • 101: .map
    • 102+: .rsc分片

和monokakido的格式很像

所以说是山寨,索引和标题文件的细节不一样。

希望能有后缀匹配。
这要在辞典格式搞定,还是在辞典软件上?

Gemini

EBWin 的 Suffix Search(后方一致查询) 在日文查询中非常实用,但它并非「只」针对日文,而是一个通用的字典搜索功能。
在日文语境下,这个功能特别受欢迎,主要原因有以下几点:

  1. 处理日文的「接尾辞」 (Suffixes)
    日文有大量的接尾语(如:~さ、~性、~主义、~放题)。如果你想研究哪些词可以用「~放题」结尾,或者查询所有以「~化」结尾的术语,使用 Suffix Search 输入「化」就能一次抓出所有结果。
  2. 汉字词汇的逆向查询
    日文汉字词汇丰富,有时候你记得某个词的结尾是「根」(例如:羽根、屋根、垣根),但不确定前面的读音或汉字时,后方一致查询能帮你快速缩小范围。
  3. 诗词、韵脚或语言学研究
    对于创作(如写俳句、歌词)或从事语言学研究的用户,这是一个查找「押韵」或相同结尾词汇的神器。

主词头要改成正反向btree混合,然后查询库代码也要改,软件的话,需要链接动态库,然后调用api就行。

po主自称山寨格式未免有些妄自菲薄了,有新产品分享出来对技术讨论是好事。
有没有可能会有从mdx转换到新格式的脚本?像我这种小白至少也可以帮忙测试下

已經實現了。

我也写了一个,欢迎交流。
https://forum.freemdict.com/t/topic/44435