Hunspell 拼写检查完全教程 / 第 04 章:词典文件格式
第 04 章:词典文件格式
4.1 双文件架构
Hunspell 词典由两个配对文件组成,缺一不可:
| 文件 | 扩展名 | 作用 |
|---|---|---|
| 词典文件(Dictionary File) | .dic | 存储词根列表及其关联的 affix 标志 |
| 词缀文件(Affix File) | .aff | 定义词缀规则、替换规则、编码、特殊标志 |
en_US.dic en_US.aff
────────────── ──────────────
abandon/DGS SET UTF-8
abandonment/S TRY esianrtolcdugmphbyfvkwz
abbreviate/XDGNS
abbreviation/SM SFX D Y 4
... SFX D 0 d e
120000 SFX D 0 ed [^e]
SFX D y ied [^aeiou]y
SFX D 0 ed [^aeiou][ey]
关键规则:.dic 文件的第一行是词典大小(可选,但推荐),最后一行可以是空行。.aff 文件必须以 SET 指令开头声明编码。
4.2 词典文件(.dic)格式
4.2.1 基本结构
词根/标志序列
词根/标志序列
...
每行一个词条,格式为:
<词根>[/<标志>]
4.2.2 简单词条
hello
world
computer
无标志的词条只有词根本身,不做词缀展开。
4.2.3 带 affix 标志的词条
run/DSG # run → runs, running, ran (D=过去式, S=复数/第三人称, G=-ing)
child/SM # child → children, child's, children's (S=复数, M=所有格)
happy/RTY # happy → happier, happiest, happily (R=比较级, T=最高级, Y=副词)
4.2.4 多标志体系
Hunspell 支持三种标志(Flag)编码方式:
| 类型 | 格式 | 每个标志 | 示例 |
|---|---|---|---|
| 单字符 | ASCII 字母/数字 | 1 字符 | /DS = 2 个标志 |
| 双字符 | 任意两个 ASCII 字符 | 2 字符 | /DS01 = 2 个标志 |
| 数字 | 0-65535 | 2-5 个数字 | /1234 = 1 个标志 |
标志类型通过 .aff 文件中的 FLAG 指令设定:
# .aff 文件中设置标志类型
FLAG long # 双字符标志(推荐,最多 65536 个)
FLAG num # 数字标志
FLAG char # 单字符标志(默认,最多 52 个)
4.2.5 双字符标志示例
# FLAG long
abandon/DS # 标志 D 和 S(2 个标志)
abbreviation/SQ # 标志 S 和 Q
abacus/S # 标志 S
4.2.6 数字标志示例
# FLAG num
abandon/1234 # 标志 1234(单个四位数标志)
abandon/12,34 # 标志 12 和 34(两个标志,用逗号分隔)
abandon/1,2,3 # 标志 1、2、3(三个标志)
注意:数字标志用逗号分隔多标志,字符标志直接连写。
4.2.7 词典大小声明
120000 # 第一行:词典大小估计(可选但推荐)
abandon/DGS
abandonment/S
...
Hunspell 使用这个值进行内部哈希表初始化。写入一个接近实际大小的数字可以提高性能。
4.2.8 特殊词条语法
# 注释行(以 # 开头)
# 这是词典中的注释
# 多形态词干(配合 FLAG num 使用)
# 词根\形态信息
# 带空格的词条需要转义
word\ with\ space/XY
4.3 词缀文件(.aff)格式
4.3.1 基本指令一览
| 指令 | 说明 | 示例 |
|---|---|---|
SET | 编码声明(必须在首行) | SET UTF-8 |
FLAG | 标志类型 | FLAG long |
TRY | 建议生成的字符优先级 | TRY esianrtolcdugm... |
SFX | 后缀规则(Suffix) | SFX D Y 4 |
PFX | 前缀规则(Prefix) | PFX U Y 1 |
REP | 常见拼写替换(用于建议) | REP 1 |
MAP | 字符等价映射 | MAP 9 |
COMPOUNDRULE | 复合词规则 | COMPOUNDRULE 2 |
COMPOUNDBEGIN | 复合词开始标志 | COMPOUNDBEGIN A |
COMPOUNDEND | 复合词结束标志 | COMPOUNDEND B |
COMPOUNDMIDDLE | 复合词中间标志 | COMPOUNDMIDDLE C |
COMPOUNDWORDMAX | 复合词最大组成部分数 | COMPOUNDWORDMAX 3 |
COMPOUNDMIN | 复合词最短组成部分长度 | COMPOUNDMIN 3 |
WORDCHARS | 视为单词一部分的字符 | WORDCHARS -' |
KEEPCASE | 禁止大小写变化的标志 | KEEPCASE K |
NOSUGGEST | 不提供拼写建议的标志 | NOSUGGEST X |
NEEDAFFIX | 必须有词缀才能独立成词 | NEEDAFFIX N |
ONLYINCOMPOUND | 只在复合词中出现 | ONLYINCOMPOUND O |
FORBIDDENWORD | 禁止的词形 | FORBIDDENWORD F |
CIRCUMFIX | 前后缀必须同时出现 | CIRCUMFIX C |
ICONV | 输入转换规则 | ICONV 1 |
OCONV | 输出转换规则 | OCONV 1 |
BREAK | 词边界断字符 | BREAK 3 |
CHECKCOMPOUNDCASE | 复合词大小写检查 | CHECKCOMPOUNDCASE |
CHECKCOMPOUNDDUP | 禁止重复词复合 | CHECKCOMPOUNDDUP |
CHECKCOMPOUNDREP | 复合词替换检查 | CHECKCOMPOUNDREP |
CHECKCOMPOUNDTRIPLE | 三连字符检查 | CHECKCOMPOUNDTRIPLE |
CHECKCOMPOUNDPATTERN | 复合词模式检查 | CHECKCOMPOUNDPATTERN 1 |
FORCEUCASE | 强制大写标志 | FORCEUCASE 1 |
LANG | 语言代码 | LANG en_US |
AF | affix 标志别名 | AF 2 |
AM | 形态学别名 | AM 3 |
4.3.2 SET 指令(编码声明)
# 必须是 .aff 文件的第一个有效指令(注释除外)
SET UTF-8 # UTF-8 编码(推荐)
SET ISO8859-1 # Latin-1 编码
SET ISO8859-15 # Latin-9 编码
SET KOI8-R # 俄语编码
SET GB2312 # 中文简体编码
4.3.3 FLAG 指令
# 单字符标志(默认,最多 52 个标志:a-z, A-Z)
FLAG char
# 双字符标志(推荐,最多 65536 个标志)
FLAG long
# 数字标志
FLAG num
4.3.4 TRY 指令
TRY 定义建议生成时字符出现的优先级。Hunspell 使用这个列表来优化"尝试替换"算法:
# 英语的 TRY 列表(按频率排序)
TRY esianrtolcdugmphbyfvkwz
# 德语
TRY ensilatrgukodcmpfhbwvzjxyq
# 法语
TRY esartnuloidcpmvfbhqgxjywzk
这个列表不影响检查的正确性,只影响建议的质量和速度。
4.3.5 REP 指令
REP 定义常见拼写错误替换模式,用于改进纠正建议:
REP 15
REP ph f # phone → fone
REP f ph # foto → photo
REP gh f # enouf → enough
REP c s # sience → science
REP s c # cieling → ceiling
REP ei ie # recieve → receive
REP ie ei # wierd → weird
REP iee ei # achive → achieve
REP oo u # becuse → because
REP ss s # neccessary → necessary
REP y i # definate → definite
REP ou u # colr → colour
REP ee e # publically → publicly
REP eee ee # publicaly → publicly
REP tt t # littel → little
格式:REP <数字>(声明条目数)后跟 REP <错误模式> <正确模式>。
4.3.6 MAP 指令
MAP 定义字符等价关系,用于建议算法中将某些字符视为"等价":
MAP 6
MAP aáâãäå # a 等价于带重音的变体
MAP eéèêë # e 等价于带重音的变体
MAP iíìîï # i 等价于带重音的变体
MAP oóòôõöø # o 等价于带重音的变体
MAP uúùûü # u 等价于带重音的变体
MAP nñ # n 等价于 ñ
效果:用户输入 cafe,Hunspell 会建议 café。
4.3.7 WORDCHARS 指令
# 指定哪些非字母字符应被视为单词的一部分
WORDCHARS -' # 连字符和撇号视为单词组成部分
# 效果: well-known 被视为一个词
# 效果: don't 被视为一个词
4.3.8 KEEPCASE 标志
# 在 .aff 文件中定义标志
KEEPCASE K
# 在 .dic 文件中使用
iPod/K # iPod 必须保持这种大小写
iPhone/K # 不能写成 ipod, IPHONE 等
4.3.9 NOSUGGEST 标志
NOSUGGEST X
# 在 .dic 文件中
shit/X # 虽然是合法词,但不提供拼写建议
fuck/X # 避免在建议列表中出现敏感词
4.3.10 NEEDAFFIX 标志
NEEDAFFIX N
# 在 .dic 文件中
un/N # "un" 不能独立使用,必须配合前缀 un-happy
4.3.11 FORBIDDENWORD 标志
FORBIDDENWORD F
# 在 .dic 文件中
teh/F # 禁止 "teh"(常见错别字,应为 the)
adn/F # 禁止 "adn"(应为 and)
4.3.12 CIRCUMFIX 标志
CIRCUMFIX C
# 在 .dic 文件中
gehen/C # 德语动词,需要同时加前缀和后缀
# SFX 规则
SFX C ge t gehen → gegangen(ge- + -t,前缀后缀同时)
# PFX 规则
PFX C ge 0 gehen
4.4 词典示例分析
4.4.1 最小英语词典
以下是一个简化的英语词典示例,帮助理解格式:
mini_en.aff:
SET UTF-8
FLAG long
# 后缀规则:复数 -s/-es
SFX S Y 2
SFX S 0 s [^sxzh] # cat → cats
SFX S 0 es [sxzh] # box → boxes
# 后缀规则:过去式 -ed
SFX D Y 4
SFX D 0 d e # love → loved
SFX D 0 ed [^e] # walk → walked
SFX D y ied [^aeiou]y # try → tried
SFX D 0 ed [aeiou]y # play → played
# 后缀规则:现在分词 -ing
SFX G Y 4
SFX G e ing e # make → making
SFX G 0 ing [^e] # walk → walking
SFX G y ying [aeiou]y # play → playing
SFX G 0 ing [^aeiou][aeiou][^aeiou]swim → swimming (双写辅音)
# 后缀规则:比较级 -er / 最高级 -est
SFX R Y 2
SFX R 0 r [^y] # tall → taller
SFX R y ier [^aeiou]y # happy → happier
SFX T Y 2
SFX T 0 st [^y] # tall → tallest
SFX T y iest [^aeiou]y # happy → happiest
# 后缀规则:副词 -ly
SFX L Y 2
SFX L 0 ly [^y] # slow → slowly
SFX L y ily [^aeiou]y # happy → happily
# 后缀规则:名词化 -ness
SFX N Y 2
SFX N 0 ness [^y] # dark → darkness
SFX N y iness [^aeiou]y # happy → happiness
# 前缀规则:否定 un-
PFX U Y 1
PFX U un 0 . # happy → unhappy, do → undo
# 建议字符频率
TRY esianrtolcdugmphbyfvkwz
# 常见替换
REP 4
REP ie ei # recieve → receive
REP ei ie # weird → wierd
REP gh f # enough → enouf
REP c s # sience → science
mini_en.dic:
10000
abandon/GDS
ability/S
able/U
about
above
abuse/GDS
accept/GDS
accident/SM
accommodate/GDS
achieve/GDS
acknowledge/GDS
acquire/GDS
across
act/GRSD
action/SM
active/SL
activity/S
actor/SM
actual/SLY
adapt/GDS
add/GRDS
addition/SM
address/SM
adequate/SLY
adjust/GDS
administration/SM
admire/GDS
admit/GDS
adult/MS
advance/GDS
advantage/MS
adventure/MS
advice/S
advise/GDRS
affair/MS
affect/GDS
afford/GDS
afraid
after
against
age/MSD
agency/S
agent/MS
aggressive/SLY
agree/GRDS
agreement/SM
ahead
aim/GRDS
air/MS
aircraft/S
alarm/MS
album/MS
alcohol/MS
alert/SGDR
alien/MS
align/GDS
alive
all
alliance/S
allow/GDS
allowance/S
almost
alone
along
already
also
alter/GDS
alternative/MS
although
altogether
always
amaze/GDS
ambition/SM
among
amount/MS
amuse/GDS
analysis/S
analyze/GDS
ancient
anger/MS
angle/MS
angry/RLY
animal/MS
anniversary/S
announce/GDRS
annual/SLY
anonymous/LY
answer/MS
anxiety/S
anxious/SLY
any
anybody/S
anymore
anyone/S
anything/S
anyway/S
anywhere
apart
apartment/SM
apologize/GDS
appeal/GDS
appear/GDS
appearance/SM
apple/MS
application/SM
apply/GDS
appoint/GDS
appointment/SM
appreciate/GDS
approach/MS
appropriate/SLY
approval/S
approve/GDS
area/MS
argue/GDS
argument/SM
arise/GDS
arm/MS
army/MS
around
arrange/GDS
arrangement/SM
arrest/SGD
arrival/S
arrive/GDS
art/MS
article/MS
artificial/SLY
artist/MS
artistic/LY
as
aside
ask/GDS
aspect/MS
assault/MS
assemble/GDS
assembly/S
assess/GDS
assessment/SM
asset/MS
assign/GDS
assignment/SM
assist/GDS
assistance/S
assistant/MS
associate/GSD
association/SM
assume/GDS
assumption/SM
assure/GDS
at
atmosphere/MS
attach/GDS
attack/MSD
attain/GDS
attempt/MSD
attend/GDS
attention/S
attitude/MS
attorney/MS
attract/GDS
attraction/MS
attractive/LY
audience/MS
author/MS
authority/S
automatic/SLY
automobile/MS
autumn/MS
available/LY
average/MS
avoid/GDS
award/MS
aware/L
away
awesome
awful/LY
4.4.2 分析这个示例
abandon/GDS 的展开过程:
GDS 标志拆解:G、D、S 三个标志
标志 G (现在分词):
abandon → abandoning(规则: SFX G 0 ing [^e])
标志 D (过去式):
abandon → abandoned(规则: SFX D 0 ed [^e])
标志 S (复数/第三人称):
abandon → abandons(规则: SFX S 0 s [^sxzh])
总计生成词形:
abandon, abandons, abandoned, abandoning
achieve/GDS 的展开过程:
标志 G:
achieve → achieving(规则: SFX G e ing e,去掉 e 加 ing)
标志 D:
achieve → achieved(规则: SFX D 0 d e,去掉 e 加 d)
标志 S:
achieve → achieves(规则: SFX S 0 s [^sxzh])
总计生成词形:
achieve, achieves, achieved, achieving
4.5 编码规范
4.5.1 编码选择建议
| 编码 | 适用场景 | 优势 | 劣势 |
|---|---|---|---|
| UTF-8 | 所有新词典 | 通用、支持所有语言 | 多字节字符匹配需特殊处理 |
| ISO-8859-1 | 西欧语言旧词典 | 单字节、简单 | 不支持非西欧字符 |
| ISO-8859-2 | 中欧语言 | 匈牙利语等 | 不支持西欧特殊字符 |
| KOI8-R | 俄语 | 俄语专用 | 不支持其他语言 |
| GB2312/GBK | 中文简体 | 中文专用 | 需要特殊分词处理 |
| Big5 | 中文繁体 | 台湾/香港 | 不兼容简体 |
4.5.2 UTF-8 中的特殊处理
# UTF-8 字符在正则表达式中需要特殊语法
# 匹配法语字符 é 的表示方式
# 在 Hunspell 正则中,多字节 UTF-8 字符用 \x{HHHH} 表示
SFX D 0 \u00e9 # é 的 Unicode 码点
# 或者直接使用 UTF-8 字符(如果文件本身是 UTF-8 编码)
SFX D 0 é
4.5.3 BOM 处理
# UTF-8 BOM (Byte Order Mark) 可能导致问题
# 确保 .dic 和 .aff 文件不带 BOM
# 检查 BOM
hexdump -C en_US.aff | head -2
# 如果第一行是 ef bb bf,则有 BOM
# 移除 BOM
sed -i '1s/^\xEF\xBB\xBF//' en_US.aff
sed -i '1s/^\xEF\xBB\xBF//' en_US.dic
4.5.4 行尾换行符
# Unix 使用 LF,Windows 使用 CRLF
# Hunspell 通常能处理两者,但建议使用 Unix 格式
# 转换为 Unix 格式
dos2unix en_US.aff en_US.dic
# 或用 sed
sed -i 's/\r$//' en_US.aff
sed -i 's/\r$//' en_US.dic
4.6 词典大小与性能
4.6.1 第一行的大小声明
# 词典文件第一行应该是词条数量(近似值)
120000 ← Hunspell 用这个值初始化哈希表
abandon/GDS
ability/S
...
4.6.2 不同语言词典规模对比
| 语言 | 词根数 | 展开后词形数 | 压缩率 |
|---|---|---|---|
| 英语(en_US) | ~50,000 | ~400,000 | 8:1 |
| 德语(de_DE) | ~300,000 | ~2,000,000 | 7:1 |
| 法语(fr) | ~60,000 | ~500,000 | 8:1 |
| 西班牙语(es) | ~50,000 | ~600,000 | 12:1 |
| 匈牙利语(hu) | ~60,000 | ~1,500,000 | 25:1 |
| 芬兰语(fi) | ~70,000 | ~15,000,000 | 214:1 |
4.6.3 性能优化建议
# 1. 保持第一行大小声明准确
wc -l en_US.dic # 查看实际行数
# 2. 对于大型词典,可以使用 affix 别名(AF/AM)减少重复
# .aff 文件中
AF 2
AF A S # 别名 A = 标志 S
AF B SD # 别名 B = 标志 S 和 D
# .dic 文件中使用别名(减少每行标志字符数)
run/B # 等价于 run/SD
4.7 复合词(Compound Words)
4.7.1 基本复合词设置
# .aff 文件中
COMPOUNDBEGIN B
COMPOUNDMIDDLE M
COMPOUNDEND E
COMPOUNDWORDMAX 3 # 最多 3 个组成部分
COMPOUNDMIN 3 # 每个部分至少 3 个字符
# .dic 文件中
house/BME # 可以出现在复合词的任何位置
boat/BME
sun/BME
这样 sunhouse、houseboat、sunhouseboat 都被认为是合法的。
4.7.2 复合词规则(COMPOUNDRULE)
# 复合词规则使用类似正则的语法
COMPOUNDRULE 2
COMPOUNDRULE BME*E # 开始 + 任意中间 + 结束
COMPOUNDRULE BE # 开始 + 结束(两词复合)
# 标志定义
COMPOUNDBEGIN B
COMPOUNDMIDDLE M
COMPOUNDEND E
4.7.3 德语复合词示例
德语是复合词的典型代表:
# de_DE.aff 中的关键设置
COMPOUNDRULE 2
COMPOUNDRULE t*et # 复合词连接符规则
COMPOUNDRULE *e* # 中间插入
COMPOUNDMIN 3
COMPOUNDWORDMAX 5
COMPOUNDSYLLABLE 6 # 复合词最多音节数
SYLLABLENUM 3 # 最大音节数
# de_DE.dic 中
Haus/t # 可作为复合词开头(标志 t)
Buch/t # 可作为复合词开头
Tür/t # 可作为复合词开头
4.8 验证词典文件
4.8.1 词典完整性检查脚本
#!/bin/bash
# validate_dict.sh - 验证 .dic 和 .aff 文件完整性
DICT_BASE="$1"
if [ ! -f "${DICT_BASE}.dic" ]; then
echo "错误: 找不到 ${DICT_BASE}.dic"
exit 1
fi
if [ ! -f "${DICT_BASE}.aff" ]; then
echo "错误: 找不到 ${DICT_BASE}.aff"
exit 1
fi
echo "=== 词典验证: $DICT_BASE ==="
# 检查 .aff 文件
echo "[.aff 文件]"
echo " 编码: $(head -1 ${DICT_BASE}.aff)"
echo " 行数: $(wc -l < ${DICT_BASE}.aff)"
echo " 标志类型: $(grep -m1 '^FLAG' ${DICT_BASE}.aff || echo '未指定(默认 char)')"
echo " SFX 规则数: $(grep -c '^SFX' ${DICT_BASE}.aff)"
echo " PFX 规则数: $(grep -c '^PFX' ${DICT_BASE}.aff)"
echo " REP 规则数: $(grep -c '^REP ' ${DICT_BASE}.aff)"
# 检查 .dic 文件
echo "[.dic 文件]"
TOTAL_LINES=$(wc -l < ${DICT_BASE}.dic)
HEADER=$(head -1 ${DICT_BASE}.dic)
if [[ "$HEADER" =~ ^[0-9]+$ ]]; then
echo " 声明大小: $HEADER"
echo " 实际词条: $((TOTAL_LINES - 1))"
else
echo " 实际词条: $TOTAL_LINES(无大小声明)"
fi
# 检查孤立标志
echo "[标志一致性检查]"
AFF_FLAGS=$(grep -oP '(?<=^SFX\s)\S+|(?<=^PFX\s)\S+' ${DICT_BASE}.aff | sort -u)
for flag in $AFF_FLAGS; do
count=$(grep -c "/.*${flag}" ${DICT_BASE}.dic 2>/dev/null || echo 0)
echo " 标志 '$flag': $count 个词条使用"
done
# 实际测试
echo "[功能测试]"
echo " 正确词: $(echo 'test' | hunspell -d "$DICT_BASE" -l 2>/dev/null | wc -l) 个错误"
echo " 错误词: $(echo 'tset' | hunspell -d "$DICT_BASE" -l 2>/dev/null | wc -l) 个错误"
echo "=== 验证完成 ==="
4.8.2 常见格式错误
| 错误 | 原因 | 修复 |
|---|---|---|
Can't open aff file | .aff 文件路径错误 | 检查文件名和路径 |
Wrong affix file | .aff 格式错误 | 检查首行 SET 指令 |
Unknown flag | 使用了未定义的标志 | 检查 SFX/PFX 定义 |
| 编码错误 | BOM 或编码不匹配 | 移除 BOM,检查 SET |
| 空建议列表 | TRY 列表缺失 | 添加 TRY 指令 |
| 性能差 | 第一行大小声明不准 | 更新 wc -l 值 |
4.9 本章小结
| 概念 | 说明 |
|---|---|
.dic 文件 | 词根 + 标志,一行一个词条 |
.aff 文件 | 词缀规则、替换规则、配置指令 |
| FLAG 类型 | char(默认)、long(推荐)、num |
| 编码 | SET UTF-8(推荐统一使用 UTF-8) |
| SFX/PFX | 后缀/前缀规则,核心的词形变化机制 |
| REP | 常见拼写错误替换,改进纠正建议 |
| TRY | 字符频率,优化建议算法 |
| 复合词 | 通过 COMPOUNDRULE 系列指令控制 |
扩展阅读
- Hunspell affix 文件规范 — 官方文档
- MySpell 格式规格 — 原始设计
- LibreOffice Wiki — Spellchecker — 词典开发指南
- Understanding Hunspell aff and dic files — 详细教程
- LanguageTool + Hunspell — 集成说明