# 码表文件格式

码表文件是一个 UTF-8 文本文件，最多可以包含以下四个部分，顺序如下：

1. 配置部分
2. 可选的组词规则部分
3. 数据部分
4. 可选的词组部分

文件同时支持英文和中文关键字：

| 英文 | 中文 |
| --- | --- |
| `KeyCode=` | `键码=` |
| `Length=` | `码长=` |
| `InvalidChar=` | `规避字符=` |
| `Pinyin=` | `拼音=` |
| `PinyinLength=` | `拼音长度=` |
| `Prompt=` | `提示=` |
| `ConstructPhrase=` | `构词=` |
| `[Rule]` | `[组词规则]` |
| `[Data]` | `[数据]` |
| `[Phrase]` | `[词组]` |

## 示例

```text
KeyCode=abcdefghijklmnopqrstuvwxy
Length=4
Pinyin=@
[Rule]
e2=p11+p12+p21+p22
e3=p11+p21+p31+p32
a4=p11+p21+p31+n11
[Data]
xycq 统
yfh 计
nnkd 局
[Phrase]
统计局
```

## 典型使用场景

### 中文码表输入法

对于五笔、仓颉、郑码以及其他形码输入法来说，码表文件通常不只是简单的
`编码 -> 文本` 对应关系。

常见需求包括：

- 在 `[Data]` 中定义单字条目
- 在 `[Rule]` 中定义组词规则
- 在 `[Phrase]` 中可选地加入常用多字词
- 可选地使用 `Pinyin=` 提供拼音辅助查询
- 可选地使用 `Prompt=` 提供拆字或字根提示
- 可选地使用 `ConstructPhrase=` 为组词提供专门的单字构词编码

这是最常见的完整功能码表格式。

### 其他语言或更简单的编码表

对于非中文输入法、符号码表、转写方案，或者任何其他简单的编码查找表，
通常只需要基本配置和 `[Data]` 部分。

典型场景包括：

- 自定义符号输入
- 简写展开
- 基于转写的词语查找
- 小型编码到文本字典

这些场景通常可以省略：

- `[Rule]`
- `[Phrase]`
- `Pinyin=`
- `Prompt=`
- `ConstructPhrase=`

最小可用形式如下：

```text
KeyCode=abcdefghijklmnopqrstuvwxyz
Length=6
[Data]
ab example
abc another
```

## 1. 配置部分

文件开头是配置行。每一行前后的空白会被忽略。去掉前导空白后，如果一行
的第一个字符是 `#`，则该行会被视为注释。这个注释规则只适用于配置和规则部分，
不适用于 `[Data]` 和 `[Phrase]` 部分。

支持的键包括：

- `KeyCode=`：必填，定义可用于编码的字符集合。
- `Length=`：普通条目的最大编码长度。
- `InvalidChar=`：定义某些编码字符不应作为单字条目的首码参与单字反查表
  的构建。它主要用于某些码表中的特殊前导编码。
- `Pinyin=`：定义 `[Data]` 中拼音条目的前缀字符。
- `Prompt=`：定义 `[Data]` 中提示条目的前缀字符。
- `ConstructPhrase=`：定义 `[Data]` 中构词条目的前缀字符。
- `PinyinLength=`：保留作兼容用途。

`[Data]` 表示配置部分结束，并开始主数据部分。

`[Rule]` 表示切换到规则部分。之后仍然必须出现 `[Data]`。

## 2. 组词规则部分

规则部分是可选的。只有在你希望自动生成词组编码时才需要。

对于五笔，`wbx.txt` 使用下面这组规则：

```text
[组词规则]
e2=p11+p12+p21+p22
e3=p11+p21+p31+p32
a4=p11+p21+p31+n11
```

规则语法如下：

- `eN=...`：当词组长度恰好为 `N` 时使用。
- `aN=...`：当词组长度大于等于 `N` 时使用。
- 等号右侧是由 `+` 连接起来的一组规则项。
- 每个规则项都由三个字符组成：
  - `p` 或 `n`：从词组前面或后面取字。
  - 第二个字符：取第几个字（`1`-`9`）。
  - 第三个字符：取该字编码中的第几个码元：
    - `1`-`9`：从前往后数
    - `z`：最后一个码元
    - `y`：倒数第二个码元
    - `x`：倒数第三个码元
    - 依此类推
- `p00` 是占位符，不产生任何码元。

例如，`p1z` 表示“取词组第一个字编码的最后一个码元”。

### 五笔规则含义

这三条规则就是 `wbx.txt` 使用的标准组词规则：

- `e2=p11+p12+p21+p22`
  - 适用于二字词
  - 取第一个字的前两个码元
  - 再取第二个字的前两个码元
- `e3=p11+p21+p31+p32`
  - 适用于三字词
  - 依次取第一、第二、第三个字的第一个码元
  - 然后再取第三个字的第二个码元
- `a4=p11+p21+p31+n11`
  - 适用于四字及以上词组
  - 取前三个字的第一个码元
  - 再取最后一个字的第一个码元

### 五笔示例：`百合 -> djwg`

假设码表中已经包含来自 `wbx.txt` 的以下单字编码：

```text
dj 百
wgk 合
```

对于一个二字词，五笔使用：

```text
e2=p11+p12+p21+p22
```

这条规则的含义是：

- `e2`：适用于 2 个字的词组
- `p11`：取第 1 个字的第 1 个码元
- `p12`：取第 1 个字的第 2 个码元
- `p21`：取第 2 个字的第 1 个码元
- `p22`：取第 2 个字的第 2 个码元

应用到 `百合` 上时：

- `百` 的编码是 `dj`，因此提供 `d` 和 `j`
- `合` 的编码是 `wgk`，因此提供 `w` 和 `g`

因此，生成的词组编码就是：

```text
百合 -> djwg
```

`[Data]` 表示规则部分结束。

## 3. 数据部分

每一条数据行都由一个 key 和一个 value 组成，中间以空白字符分隔：

```text
<key> <value>
```

例如：

```text
a 日
aa 昌
abac 暝
```

普通条目的 `<key>` 只能使用 `KeyCode=` 中列出的字符。

如果配置了 `Pinyin=`、`Prompt=` 或 `ConstructPhrase=`，那么 key 可以以前缀
字符开头：

```text
@ni 你
&a 日
^cq 统
```

这些分别表示：

- `@ni 你`：`你` 的拼音条目
- `&a 日`：编码 `a` 的提示文本
- `^cq 统`：用于组词的构词编码

需要注意：

- key 不能为空。
- `Prompt=` 条目提供提示文本，不属于普通候选词条。
- `ConstructPhrase=` 条目只用于组词编码生成，本身不会作为普通候选词条插入。
- 空行或格式错误的数据行会被忽略。
- 在 `[Data]` 中，`#` **不是** 注释标记；除非它让这一行格式非法，否则它就只是普通文本。

## 4. 词组部分

`[Phrase]` 是可选的，并且只能出现在 `[Data]` 之后。只有在规则部分存在
时，它才有效。

后续每一行都只写词组本身：

```text
[Phrase]
统计局
中华人民共和国
```

词组编码会根据 `[Rule]` 和前面已经定义好的单字条目自动生成。

一旦进入 `[Phrase]`，后面所有行都会被当作词组处理。

## 转义

`[Data]` 中的 value，以及 `[Phrase]` 中的整行内容，都可以使用带引号的形式。
当值中包含空白字符、`"` 或 `\` 时，建议使用引号。

文件中的每一条记录仍然是按“行”组织的：一个条目占用一个物理行。
真正的多行条目不能直接以原始多行文本写在文件中。

如果希望一个值内部包含换行，可以在带引号的字符串中使用转义，例如 `\n`。

例如：

```text
aaaa "工 "
f "\""
note "first line\nsecond line"
[Phrase]
"统计局"
```

带引号的值支持反斜杠转义，包括：

- `\"`：字面意义上的双引号
- `\\`：字面意义上的反斜杠
- `\n`：嵌入式换行

所以：

```text
note "first line\nsecond line"
```

表示的是一个内部包含两行内容的单个值，虽然码表文件本身仍然只占一行。

## 要求与限制

- 文件必须是合法的 UTF-8。
- `KeyCode=` 不能包含已经配置给 `Pinyin=`、`Prompt=` 或 `ConstructPhrase=` 的前缀字符。
- 数据条目的 key 不能为空。
- `[Data]` 是必需的。
- `[Phrase]` 必须依赖规则部分。
