强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

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-655352-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
AFaffix 标志别名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,0008:1
德语(de_DE)~300,000~2,000,0007:1
法语(fr)~60,000~500,0008:1
西班牙语(es)~50,000~600,00012:1
匈牙利语(hu)~60,000~1,500,00025:1
芬兰语(fi)~70,000~15,000,000214: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

这样 sunhousehouseboatsunhouseboat 都被认为是合法的。

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 系列指令控制

扩展阅读