输入法词库解析(七)微软用户自定义短语.dat

张春  金牌会员 | 2022-9-18 03:31:50 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 687|帖子 687|积分 2061

详细代码:https://github.com/cxcn/dtool
前言

微软拼音和微软五笔通用的用户自定义短语 dat 格式。
解析


前 8 个字节标识文件格式 machxudp,微软五笔的 lex 格式是 imscwubi。
下面 8 个字节应该是版本号。
接下来每 4 字节一组,分别表示偏移表开始词条开始文件总长词条数导出的时间戳
然后补 0 一直到偏移表开始
偏移表记录了每个词条从词条开始的偏移量,每 4 个字节一组。
接下来就是词条本体部分:
#占用字节数描述410 00 10 00 标记a2该词条总字节长 - 词占用的字节长1在候选中的位置10x06或0x13,未知404从2010-01-01开始的时间戳a - 16编码(utf-16le),00 标识结束词条总字节长 - a词(utf-16le),00 标识结束代码实现:
  1. func (MsUDP) Parse(filename string) Table {
  2.     data, _ := os.ReadFile(filename)
  3.     r := bytes.NewReader(data)
  4.     ret := make(Table, 0, r.Len()>>8)
  5.     // 词库偏移量
  6.     r.Seek(0x10, 0)
  7.     offset_start := ReadUint32(r) // 偏移表开始
  8.     entry_start := ReadUint32(r)  // 词条开始
  9.     entry_end := ReadUint32(r)    // 词条结束
  10.     entry_count := ReadUint32(r)  // 词条数
  11.     export_time := ReadUint32(r)  // 导出的时间
  12.     t := time.Unix(int64(export_time), 0)
  13.     fmt.Println(t, entry_end)
  14.     // 第一个偏移量
  15.     offset := 0
  16.     for i := 0; i < entry_count; i++ {
  17.         var next, length int
  18.         if i == entry_count-1 {
  19.             length = entry_end - entry_start - offset
  20.         } else {
  21.             r.Seek(int64(offset_start+4*(i+1)), 0)
  22.             next = ReadUint32(r)
  23.             length = next - offset
  24.         }
  25.         // fmt.Println(offset, next, length)
  26.         r.Seek(int64(offset+entry_start), 0)
  27.         offset = next
  28.         ReadUint32(r)            // 0x10001000
  29.         codeLen := ReadUint16(r) // 编码字节长+0x12
  30.         order, _ := r.ReadByte() // 顺序
  31.         _, _ = r.ReadByte()      // 0x06 不明
  32.         ReadUint32(r)            // 4 个空字节
  33.         ReadUint32(r)            // 时间戳
  34.         tmp := make([]byte, codeLen-0x12)
  35.         r.Read(tmp)
  36.         code, _ := util.Decode(tmp, "UTF-16LE")
  37.         ReadUint16(r) // 两个空字节
  38.         tmp = make([]byte, length-codeLen-2)
  39.         r.Read(tmp)
  40.         word, _ := util.Decode(tmp, "UTF-16LE")
  41.         fmt.Println(code, word)
  42.         ret = append(ret, Entry{word, code, order})
  43.     }
  44.     return ret
  45. }
复制代码
生成

只需注意文件总长先用空字节代替,最后才写入。
代码实现:
  1. func (MsUDP) Gen(table Table) []byte {
  2.     var buf bytes.Buffer
  3.     stamp := util.GetUint32(int(time.Now().Unix()))
  4.     buf.Write([]byte{0x6D, 0x73, 0x63, 0x68, 0x78, 0x75, 0x64, 0x70,
  5.         0x02, 0x00, 0x60, 0x00, 0x01, 0x00, 0x00, 0x00})
  6.     buf.Write(util.GetUint32(0x40))
  7.     buf.Write(util.GetUint32(0x40 + 4*len(table)))
  8.     buf.Write(make([]byte, 4)) // 待定 文件总长
  9.     buf.Write(util.GetUint32(len(table)))
  10.     buf.Write(stamp)
  11.     buf.Write(make([]byte, 28))
  12.     buf.Write(make([]byte, 4))
  13.     words := make([][]byte, 0, len(table))
  14.     codes := make([][]byte, 0, len(table))
  15.     sum := 0
  16.     for i := range table {
  17.         word, _ := util.Encode([]byte(table[i].Word), "UTF-16LE")
  18.         code, _ := util.Encode([]byte(table[i].Code), "UTF-16LE")
  19.         words = append(words, word)
  20.         codes = append(codes, code)
  21.         if i != len(table)-1 {
  22.             sum += len(word) + len(code) + 20
  23.             buf.Write(util.GetUint32(sum))
  24.         }
  25.     }
  26.     for i := range table {
  27.         buf.Write([]byte{0x10, 0x00, 0x10, 0x00})
  28.         // fmt.Println(words[i], len(words[i]), codes[i], len(codes[i]))
  29.         buf.Write(util.GetUint16(len(codes[i]) + 18))
  30.         buf.WriteByte(table[i].Order)
  31.         buf.WriteByte(0x06)
  32.         buf.Write(make([]byte, 4))
  33.         buf.Write(stamp)
  34.         buf.Write(codes[i])
  35.         buf.Write([]byte{0, 0})
  36.         buf.Write(words[i])
  37.         buf.Write([]byte{0, 0})
  38.     }
  39.     b := buf.Bytes()
  40.     copy(b[0x18:0x1c], util.GetUint32(len(b)))
  41.     return b
  42. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

张春

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表