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

Hunspell 拼写检查完全教程 / 第 05 章:词缀规则详解

第 05 章:词缀规则详解

5.1 词缀规则概述

词缀规则(Affix Rules)是 Hunspell 的核心机制。它允许从少量词根生成大量词形,极大压缩词典体积。

词根: "run"       →  运行 SFX 规则  →  run, runs, running, ran
词根: "happy"     →  运行 SFX 规则  →  happy, happier, happiest, happily, happiness
词根: "unhappy"   →  运行 PFX+SFX   →  unhappy, unhappier, unhappiest, unhappily

每条规则由以下部分组成:

[类型] [标志] [可组合] [条目数]
[类型] [标志] [条件] [删除] [添加] [匹配条件]

5.2 SFX(后缀规则)

5.2.1 语法格式

SFX <标志> <可组合(Y/N)> <条目数>
SFX <标志> <删除> <添加> [匹配条件]
字段说明
标志单个标志字符(如 D、S、G)
可组合Y = 可与其他 SFX 组合;N = 不可组合
条目数后续规则行的数量
删除从词根末尾删除的字符(0 表示不删除)
添加添加到词根末尾的字符(0 表示不添加)
匹配条件正则表达式,匹配词根的末尾字符(可选)

5.2.2 英语过去式规则详解

SFX D Y 4
SFX D   0   d       e
SFX D   0   ed      [^e]
SFX D   y   ied     [^aeiou]y
SFX D   0   ed      [aeiou]y

逐行解析:

规则 1: SFX D  0  d  e
  含义: 如果词根以 'e' 结尾,删除 ''(不删除),添加 'd'
  示例: love → love + d = loved
        dance → dance + d = danced

规则 2: SFX D  0  ed  [^e]
  含义: 如果词根不以 'e' 结尾,删除 '',添加 'ed'
  示例: walk → walk + ed = walked
        play → play + ed = played(注意:此规则也被 [aeiou]y 匹配,但规则3优先)

规则 3: SFX D  y  ied  [^aeiou]y
  含义: 如果词根以 辅音+y 结尾,删除 'y',添加 'ied'
  示例: try → tr + ied = tried
        carry → carr + ied = carried

规则 4: SFX D  0  ed  [aeiou]y
  含义: 如果词根以 元音+y 结尾,删除 '',添加 'ed'
  示例: play → play + ed = played
        enjoy → enjoy + ed = enjoyed

规则匹配顺序:Hunspell 从第一条规则开始尝试,第一条匹配的规则生效。

5.2.3 英语复数规则详解

SFX S Y 3
SFX S   0   s       [^sxzh]
SFX S   0   es      [sxzh]
SFX S   y   ies     [^aeiou]y
规则 1: cat → cats, dog → dogs, book → books
规则 2: box → boxes, church → churches, wish → wishes, buzz → buzzes
规则 3: fly → flies, city → cities, baby → babies

例外(需要手动在 .dic 中处理):
  child → children(不规则,直接写 child/SM 中 S 标志不对,需要手动处理)
  mouse → mice(不规则,直接在 .dic 中列出)

5.2.4 现在分词规则详解

SFX G Y 4
SFX G   e   ing     e
SFX G   0   ing     [^e]
SFX G   y   ying    [aeiou]y
SFX G   0   ing     [^aeiou][aeiou][^aeiou]
规则 1: make → mak + ing = making, dance → danc + ing = dancing
规则 2: walk → walk + ing = walking, run → run + ing = running
规则 3: play → play + ing = playing(元音+y 保持 y)
规则 4: swim → swim + ing = swimming(单音节 CVC 结构双写末辅音)

注意:规则 4 的 [^aeiou][aeiou][^aeiou] 匹配"辅音+元音+辅音"结构,
只适用于重读闭音节。规则简化处理,部分不规则需手动处理。

5.2.5 组合标志示例

当一个词根有多个标志时,每个标志独立展开:

# .dic 文件
run/DGS

# 展开结果:
# D: run → ran(不规则,这里只是示意;实际需要额外处理)
# G: run → running
# S: run → runs
# D+G: 一般不组合
# 所有组合:run, runs, running, ran(ran 需要手动处理或用 PFX 规则)

5.2.6 可组合标志(Y/N)

# Y = 可与其他后缀组合
SFX D Y 4        # 过去式可与其他后缀组合
SFX D 0 d e      # loved → lovedly? 不常见,但结构上允许

# N = 不可与其他后缀组合
SFX S N 3        # 复数不再与后缀组合
SFX S 0 s [^sxzh] # cats → cats,不会继续加后缀

实际使用中,Y 主要用于动词词缀(可组合 -ly, -ness 等),N 用于名词/形容词词缀。


5.3 PFX(前缀规则)

5.3.1 语法格式

PFX <标志> <可组合(Y/N)> <条目数>
PFX <标志> <删除> <添加> [匹配条件]

与 SFX 完全对称,只是作用于词根的开头。

5.3.2 英语否定前缀 un-

PFX U Y 1
PFX U   un  0       .
解析:
  标志: U
  可组合: Y
  条目数: 1
  删除: un
  添加: 0(不添加前缀)
  条件: .(匹配任意词根)

效果:
  unhappy → happy(去前缀 un)
  undo → do(去前缀 un)

注意:这是"反向"规则,用于从派生词找到词根。
但实际使用时,词根 happy 带 U 标志:
  .dic: happy/UR
  则 happy 会通过 PFX U 规则生成 unhappy

5.3.3 英语否定前缀系列

PFX U Y 2
PFX U   un  0       .

PFX I Y 2
PFX I   in  0       .
PFX I   im  0       [bmp]        # impossible, immobile, irregular

PFX N Y 1
PFX N   non 0       .

PFX M Y 1
PFX M   mis 0       .

PFX D Y 1
PFX D   dis 0       .

PFX R Y 1
PFX R   re  0       .
# .dic 文件使用
happy/UIR       # happy → unhappy (U), 不变 (I), happy → rehappy? (R)
possible/IR     # possible → impossible (I), repossible? (R)
spell/MR        # spell → misspell (M), respell (R)

5.3.4 语序问题

前缀和后缀的应用顺序:先应用前缀,再应用后缀

unhappy + -ness:
  Step 1: PFX U → un + happy = unhappy
  Step 2: SFX N → unhappy + ness = unhappiness

但 unhappiness 在词典中需要:
  happy/UNR    # U=un-前缀, N=-ness后缀, R=re-前缀

5.4 条件替换(Conditional Replacement)

条件替换是 Hunspell 的独特功能,允许在添加词缀的同时修改词根。

5.4.1 替换原理

标准规则: 词根 + 删除 + 添加
条件替换: 词根匹配条件 → 删除词根末尾 → 添加新字符

5.4.2 英语 -able/-ible 规则

SFX B Y 4
SFX B   0   able    [^aeiou]     # 以辅音结尾:work → workable
SFX B   e   able    e            # 以 e 结尾:love → lovable
SFX B   0   able    [aeiou]      # 以元音结尾:enjoy → enjoyable
SFX B   0   ible    .*           # 通用:access → accessible(需手动判断)

5.4.3 西班牙语动词变位示例

# 西班牙语 -ar 动词(hablar, 说)
SFX A Y 6
SFX A   ar  o       ar            # hablo(我)
SFX A   ar  as      ar            # hablas(你)
SFX A   ar  a       ar            # habla(他/她)
SFX A   ar  amos    ar            # hablamos(我们)
SFX A   ar  áis     ar            # habláis(你们)
SFX A   ar  an      ar            # hablan(他们/她们)

# 西班牙语 -er 动词(comer, 吃)
SFX E Y 6
SFX E   er  o       er            # como
SFX E   er  es      er            # comes
SFX E   er  e       er            # come
SFX E   er  emos    er            # comemos
SFX E   er  éis     er            # coméis
SFX E   er  en      er            # comen

5.4.4 法语动词变位示例

# 法语 -er 动词现在时(parler, 说)
SFX A Y 6
SFX A   er  e       er            # je parle
SFX A   er  es      er            # tu parles
SFX A   er  e       er            # il/elle parle
SFX A   er  ons     er            # nous parlons
SFX A   er  ez      er            # vous parlez
SFX A   er  ent     er            # ils/elles parlent

# 法语阴性词尾
SFX F Y 2
SFX F   e   e       e             # 以 e 结尾不变(如 jaune 阴性仍为 jaune)
SFX F   0   e       [^e]          # 以非 e 结尾加 e(如 grand → grande)

5.4.5 德语名词复数规则

# 德语名词复数(多种模式)
SFX P Y 5
SFX P   0   e       [^aeiou]hlnr  # Stuhl → Stühle(需要 umlaut)
SFX P   0   \u00FCe  [aou]hlnr    # 对应 umlaut 变化
SFX P   0   er      [^aeiou]      # Kind → Kinder
SFX P   0   n       e             # Lampe → Lampen
SFX P   0   en      [^e]          # Tisch → Tische

5.5 跨语言词缀规则对比

5.5.1 各语言形态复杂度

语言词缀类型特殊难点
英语后缀为主不规则动词(go→went)需手动列出
德语后缀+前缀+复合元音变音(Umlaut)、格变化
法语后缀+前缀动词变位丰富、性数一致
西班牙语后缀为主动词变位极其丰富(14 时态)
俄语后缀为主6 种格变化、3 种性
匈牙利语后缀为主18 种格后缀、极度黏着
芬兰语后缀为主15 种格、高度屈折
土耳其语后缀为主元音和谐、极度黏着
阿拉伯语词根模板三辅音词根模式
日语助词动词活用形变化

5.5.2 匈牙利语后缀系统示例

# 匈牙利语格后缀(以 ház/house 为例)
SFX C Y 6
SFX C   0   ban     [^aáeéiíoóöőuúüű]    # házban (inessive)
SFX C   0   ból     [^aáeéiíoóöőuúüű]    # házból (elative)
SFX C   0   ba      [^aáeéiíoóöőuúüű]    # házba (illative)
SFX C   0   nak     [^aáeéiíoóöőuúüű]    # háznak (dative)
SFX C   0   val     [^aáeéiíoóöőuúüű]    # házzal (instrumental, 同化 z+v=z)
SFX C   0   t       [^aáeéiíoóöőuúüű]    # háztól (ablative)

# 匈牙利语的元音和谐规则使后缀选择取决于词根元音
# 后元音词: ház → házban
# 前元音词: kert → kertben

5.5.3 阿拉伯语词根模板

# 阿拉伯语基于三辅音词根的模板系统
# 词根 k-t-b (写) 可生成:
#   kitāb (书)    - 模式 CiCāC
#   kātib (作者)  - 模式 CāCiC
#   maktab (办公室) - 模式 maCCaC
#   kataba (他写了) - 模式 CaCVCV

# Hunspell 对此支持有限,通常需要:
# 1. 枚举所有模板
# 2. 使用大量手动词干条目
# 3. 或使用其他工具(如 qutrub)

5.5.4 俄语名词变格示例

# 俄语阳性名词第一格变格(以 стол/stol 为例)
# стол (table) - 第一变格法
SFX G Y 6
SFX G   0   а       .             # стол → стола (属格)
SFX G   0   у       .             # стол → столу (与格)
SFX G   0   ом      .             # стол → столом (工具格)
SFX G   0   е       .             # стол → столе (前置格)
SFX G   0   ы       [^гжкхцчшщ]  # стол → столы (复数主格)
SFX G   0   и       [гжкхцчшщ]   # парк → парки (复数主格)

# 俄语阴性名词(以 книга/kniga 为例)
SFX F Y 6
SFX F   а   и       а             # книга → книги (属格)
SFX F   а   е       а             # книга → книге (与格)
SFX F   а   у       а             # книгу (宾格)
SFX F   а   ой      а             # книгой (工具格)
SFX F   а   е       а             # книге (前置格)
SFX F   а   и       а             # книги (复数)

5.6 高级词缀技术

5.6.1 CIRCUMFIX(前后缀同时)

# CIRCUMFIX 指定前后缀必须同时出现

# 德语完成时态 ge- + -t
CIRCUMFIX C

SFX C Y 1
SFX C   en  t       en            # machen → gemacht(ge- + mach + -t)

PFX C Y 1
PFX C   ge  0       .

# .dic 文件中
machen/C    # 必须同时有 ge- 前缀和 -t 后缀 → gemacht

5.6.2 NEEDAFFIX(必须有词缀)

NEEDAFFIX N

# .dic 文件中
un/N          # "un" 不能独立存在,必须与其他规则组合
dis/N         # "dis" 不能独立存在

# 效果:
# 单独检查 "un" → 标记为错误
# "undo" 中的 "un-" 前缀 → 允许(因为 do 提供了词干)

5.6.3 ONLYINCOMPOUND(仅复合词中出现)

ONLYINCOMPOUND O

# .dic 文件中
haus/O        # "haus" 只能在复合词中使用,不能独立存在
buch/O        # "buch" 只能在复合词中使用

# 单独检查 "haus" → 错误
# 复合词 "schulhaus" → 正确

5.6.4 FORCEUCASE(强制大写)

FORCEUCASE 1

# 用于语言代码标记等特殊场景
# .dic 文件中
i/1           # "I" 必须大写(英语人称代词)

5.6.5 KEEPCASE(保持大小写)

KEEPCASE K

# .dic 文件中
iPhone/K      # 必须保持 "iPhone" 大小写
macOS/K       # 必须保持 "macOS"
McDonald/K    # 必须保持 "McDonald"

# 效果:
# iPhone → 正确 ✓
# iphone → 错误 ✗
# IPHONE → 错误 ✗

5.6.6 NOSUGGEST(不提供建议)

NOSUGGEST X

# .dic 文件中
# 避免敏感词出现在建议列表
damn/X
hell/X
bastard/X

# 效果:
# 检查 "dam" → 会建议 "dam" 但不会建议 "damn"
# 用户主动输入 "damn" → 标记为正确(不报错)

5.7 正则匹配条件

5.7.1 基础正则语法

Hunspell 的匹配条件使用类似正则表达式的语法:

语法含义示例
.任意字符. 匹配任何词根
[abc]字符集[aeiou] 匹配元音
[^abc]排除字符集[^aeiou] 匹配辅音
[a-z]范围[a-z] 匹配小写字母
[A-Z]范围[A-Z] 匹配大写字母

5.7.2 UTF-8 模式下的特殊语法

# UTF-8 编码时,特殊字符需要使用 Unicode 转义
SET UTF-8

# 匹配德语元音变音
SFX P Y 1
SFX P   0   \u00FCber  [aou]       # u → ü 的 umlaut

# 匹配法语重音字符
SFX E Y 1
SFX E   er  \u00E9      e          # e → é

5.7.3 匹配条件示例

# 匹配以 "s", "x", "z", "sh", "ch", "tch" 结尾的词
SFX S Y 2
SFX S   0   es      [sxz]          # box → boxes, quiz → quizzes
SFX S   0   es      .*[hs]         # church → churches, bush → bushes

# 匹配辅音+y 结尾
SFX S Y 1
SFX S   y   ies     [^aeiou]y      # city → cities(y 前是辅音)

# 匹配以 "o" 结尾的词(部分加 es)
SFX S Y 2
SFX S   0   es      [o]            # potato → potatoes, hero → heroes
SFX S   0   s       [^o]           # 其他:piano → pianos

5.8 规则调试与测试

5.8.1 测试单个规则

# 创建最小测试词典
cat > /tmp/test.aff << 'EOF'
SET UTF-8
FLAG long
SFX D Y 4
SFX D   0   d       e
SFX D   0   ed      [^e]
SFX D   y   ied     [^aeiou]y
SFX D   0   ed      [aeiou]y
EOF

cat > /tmp/test.dic << 'EOF'
5
love/D
walk/D
try/D
play/D
run/D
EOF

# 测试展开
echo "loved" | hunspell -d /tmp/test -l      # 无输出 = 正确
echo "walked" | hunspell -d /tmp/test -l     # 无输出 = 正确
echo "tried" | hunspell -d /tmp/test -l      # 无输出 = 正确
echo "played" | hunspell -d /tmp/test -l     # 无输出 = 正确

# 测试形态学
echo "loved" | hunspell -d /tmp/test -m
# loved st:love ts:past_tense

5.8.2 调试工具脚本

#!/bin/bash
# debug_affix.sh - 调试词缀规则
# 用法: ./debug_affix.sh <dic_base> <test_word>

DICT_BASE="$1"
TEST_WORD="$2"

echo "=== 词缀规则调试 ==="
echo "词典: $DICT_BASE"
echo "测试词: $TEST_WORD"
echo ""

# 检查是否在词典中
echo "[直接检查]"
echo "$TEST_WORD" | hunspell -d "$DICT_BASE" -l
if [ $? -eq 0 ] && [ -z "$(echo "$TEST_WORD" | hunspell -d "$DICT_BASE" -l)" ]; then
    echo "  ✓ 词典中存在"
else
    echo "  ✗ 词典中不存在"
fi

echo ""
echo "[形态分析]"
echo "$TEST_WORD" | hunspell -d "$DICT_BASE" -m

echo ""
echo "[词干提取]"
echo "$TEST_WORD" | hunspell -d "$DICT_BASE" -s

echo ""
echo "[建议]"
echo "$TEST_WORD" | hunspell -a -d "$DICT_BASE" | grep "^&"

5.8.3 规则冲突检测

# 检查是否有重复/冲突的规则
grep -P '^SFX\s+(\S+)' test.aff | awk '{print $2}' | sort | uniq -c | sort -rn | head
# 如果同一标志出现超过一次,可能存在冲突

# 检查规则是否覆盖所有预期词形
cat > /tmp/test_words.txt << 'EOF'
walks
walked
walking
walks
tries
tried
trying
loves
loved
loving
EOF

echo "=== 规则覆盖测试 ==="
while read word; do
    result=$(echo "$word" | hunspell -d /tmp/test -l)
    if [ -z "$result" ]; then
        echo "  ✓ $word"
    else
        echo "  ✗ $word (未识别)"
    fi
done < /tmp/test_words.txt

5.9 常见模式速查表

5.9.1 英语常用模式

后缀规则适用词根示例
-s/-esSFX S名词复数cats, boxes, cities
-edSFX D动词过去式walked, loved, tried
-ingSFX G动词现在分词walking, making, running
-erSFX R比较级taller, happier
-estSFX T最高级tallest, happiest
-lySFX L副词slowly, happily
-nessSFX N名词化darkness, happiness
-mentSFX M名词化development
-tion/-sionSFX O名词化education, decision
-able/-ibleSFX B形容词workable, accessible
-fulSFX F形容词beautiful, hopeful
-lessSFX X形容词hopeless, careless
-ousSFX U形容词dangerous, nervous
-ing (名)SFX I名词化building, reading

5.9.2 前缀规则速查

前缀标志含义示例
un-PFX U否定/撤销unhappy, undo
re-PFX R重复rewrite, redo
dis-PFX D否定disagree, dislike
mis-PFX M错误misspell, misfire
over-PFX V过度overcook, overuse
under-PFX W不足undercook, underuse
pre-PFX P之前preview, precondition
post-PFX Q之后postwar, postpone
in-/im-PFX I否定impossible, invisible
non-PFX Nnonsense, nonprofit
anti-PFX A反对antibiotic, antisocial
inter-PFX T之间international
trans-PFX X跨越transport, transform

5.10 本章小结

概念说明
SFX后缀规则,作用于词根末尾
PFX前缀规则,作用于词根开头
可组合 (Y/N)Y 允许与其他后缀叠加
条件替换删除词根末尾字符再添加
匹配条件正则表达式,匹配词根末尾
CIRCUMFIX前后缀必须同时出现
NEEDAFFIX词根必须有词缀才能独立成词
KEEPCASE强制保持特定大小写
NOSUGGEST不在建议列表中出现

扩展阅读