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

Hunspell 拼写检查完全教程 / 第 03 章:基本使用

第 03 章:基本使用

3.1 命令行基础

Hunspell 的命令行工具是日常使用的核心。基本语法如下:

hunspell [选项] [文件...]

3.1.1 最简单的用法

# 检查单个文件
hunspell document.txt

# 指定词典
hunspell -d en_US document.txt

# 检查多个文件
hunspell file1.txt file2.txt file3.md

3.1.2 核心参数一览

参数 说明 示例
-d dict 指定词典 -d en_US-d /path/to/en_US
-D 列出可用词典及搜索路径 hunspell -D
-l 只输出拼写错误的单词 hunspell -l file.txt
-a 管道模式(ispell 兼容) echo "test" | hunspell -a
-c 交互式更正模式 hunspell -c file.txt
-G 只打印正确的单词 hunspell -G file.txt
-L num 限制建议数量 -L 5
-m 输出词干/形态分析 hunspell -m file.txt
-M 输出形态学分解 hunspell -M file.txt
-s 词干模式 hunspell -s file.txt
-i enc 指定输入编码 -i UTF-8
-p dict 指定个人词典 -p ~/.my_dict
-w 输出拼写错误的行(含上下文) hunspell -w file.txt
-t TeX/LaTeX 模式 hunspell -t paper.tex
-H HTML 模式 hunspell -H page.html
-n nroff/troff 模式 hunspell -n manpage.1
-1 第一个建议自动替换 管道模式

3.2 交互模式

交互模式是 Hunspell 最传统的使用方式,逐个提示拼写错误的单词并提供更正选项。

3.2.1 启动交互模式

hunspell -c document.txt

3.2.2 交互界面解析

& errorr 3 0: error, errors, errata

这个输出的含义:

字段 含义
& 标记符 表示有建议的拼写错误
errorr 错误词 在文本中检测到的词
3 建议数 共有 3 个建议
0 偏移量 在该行中的位置
: error, errors, errata 建议列表 逗号分隔的候选更正

3.2.3 交互命令

在交互模式下,可以使用以下命令:

命令 说明
数字 选择对应编号的建议替换
空格 跳过,不做更正
r + 文本 手动输入替换词
a 接受该词,添加到会话词典
A 接受该词,添加到个人词典
i 接受该词(小写形式),添加到个人词典
u 接受该词(词根形式),添加到个人词典
q 退出,保存更改到文件
x 退出,不保存更改
? 显示帮助

3.2.4 交互模式示例

# 创建测试文件
cat > /tmp/test.txt << 'EOF'
This sentense has a few typose in it.
The quik brown fox jumps over the lazzy dog.
EOF

# 启动交互检查
hunspell -c /tmp/test.txt

交互过程:

& sentense 2 0: sentence, sentences
  输入: 1          ← 选择 "sentence"

& typose 2 0: typos, types
  输入: 1          ← 选择 "typos"

& quik 7 0: quick, quirk, Quik, quiche, quid, quit, quiz
  输入: 1          ← 选择 "quick"

& lazzy 3 0: lazy, dazedly, laze
  输入: 1          ← 选择 "lazy"

3.3 管道模式(-a)

管道模式输出机器可读的结果,适合脚本和自动化场景。

3.3.1 基本用法

# 管道模式
echo "helo wrld" | hunspell -a -d en_US

输出:

@(#) International Ispell Version 3.2.06 (but really Hunspell 1.7.2)
& helo 4 0: hello, Helo, helot, help
& wrld 3 0: world, wold, weld

*

3.3.2 输出格式详解

管道模式的每一行以特殊字符开头:

前缀 格式 含义
* * 单词正确
& & word count offset: sug1, sug2, ... 有建议的错误
# # word offset 无建议的错误
+ + word offset 词根正确,但词缀错误
- - word offset 根词可能正确(近似)
@ @ word 词干信息
! ! 首行,显示版本信息
`` 空行 单词分隔(每个输入词对应一个结果行)

3.3.3 提取错误单词列表

# 只获取错误的单词(去重排序)
cat document.txt | hunspell -d en_US -l | sort -u

# 统计错误数量
cat document.txt | hunspell -d en_US -l | wc -l

# 只输出正确的单词
cat document.txt | hunspell -d en_US -G | sort -u

3.3.4 获取建议并自动替换

# 使用 -a 模式解析建议(awk 处理)
echo "helo wrld" | hunspell -a -d en_US | awk '
/^&/ {
    split($0, parts, ":");
    split(parts[2], sugs, ",");
    gsub(/^ /, "", sugs[1]);  # 取第一个建议
    print $2 " → " sugs[1];
}
'
# 输出:
# helo → hello
# wrld → world

3.4 批量检查

3.4.1 检查多个文件

# 检查目录下所有 .txt 文件
find /docs -name "*.txt" -exec hunspell -l -d en_US {} \;

# 检查所有 Markdown 文件
find . -name "*.md" -exec hunspell -l -d en_US {} \; | sort -u

# 并行检查(使用 xargs 加速)
find . -name "*.md" -print0 | xargs -0 -P 4 -I{} sh -c 'hunspell -l -d en_US "$1"' _ {}

3.4.2 递归检查并报告

#!/bin/bash
# spellcheck_dir.sh - 递归检查目录下所有文本文件
# 用法: ./spellcheck_dir.sh <目录> [词典]

DIR="${1:-.}"
DICT="${2:-en_US}"
TOTAL_ERRORS=0

echo "=== Hunspell 批量拼写检查 ==="
echo "目录: $DIR"
echo "词典: $DICT"
echo "─────────────────────────────"

while IFS= read -r -d '' file; do
    errors=$(hunspell -l -d "$DICT" "$file" 2>/dev/null | wc -l)
    if [ "$errors" -gt 0 ]; then
        echo "[$errors 错误] $file"
        hunspell -l -d "$DICT" "$file" 2>/dev/null | sort -u | sed 's/^/  → /'
        TOTAL_ERRORS=$((TOTAL_ERRORS + errors))
    fi
done < <(find "$DIR" -type f \( -name "*.txt" -o -name "*.md" -o -name "*.html" \) -print0)

echo "─────────────────────────────"
echo "总计: $TOTAL_ERRORS 个拼写错误"

3.4.3 生成拼写报告

#!/bin/bash
# spell_report.sh - 生成拼写检查报告
# 输出格式:文件名:行号: 错误词

REPORT_FILE="spell_report.txt"
DICT="en_US"

> "$REPORT_FILE"  # 清空报告文件

while IFS= read -r -d '' file; do
    # -w 参数输出错误行及行号
    hunspell -w -d "$DICT" "$file" 2>/dev/null | \
    grep -E "^[^*#]" | \
    while read -r line; do
        echo "$file: $line" >> "$REPORT_FILE"
    done
done < <(find . -type f -name "*.md" -print0)

# 统计汇总
echo "拼写检查报告 - $(date)"
echo "=========================="
cat "$REPORT_FILE"
echo ""
echo "共 $(wc -l < "$REPORT_FILE") 处疑似拼写错误"

3.5 自定义词典

3.5.1 个人词典(Personal Dictionary)

个人词典用于存储 Hunspell 无法识别但你确认正确的单词:

# 使用 -p 参数指定个人词典
hunspell -p ~/.hunspell_personal -d en_US document.txt

个人词典格式:

# ~/.hunspell_personal
# 每行一个单词,可带 affix 标志
# 第一行可以是字符集标记
ISO8859-1       # 或 UTF-8
Hunspell        # 接受的专有名词
API/M           # API 及其复数形式 APIs(M 标志)
Golang          # 编程语言名

3.5.2 在交互模式中添加单词

# 启动交互模式
hunspell -c -p ~/.my_dict document.txt

# 当提示某个词时,输入以下命令:
# A — 添加到个人词典
# i — 添加小写形式
# u — 添加词根形式

3.5.3 命令行直接添加

# 创建/追加到词典文件
echo "Hunspell" >> ~/.hunspell_personal
echo "API" >> ~/.hunspell_personal

# 使用会话词典(临时,不写入文件)
echo "testword" | hunspell -a -d en_US -p /dev/null

3.5.4 多词典管理

# 按项目管理词典
PROJECT_DICT=".hunspell_project"

# 检查时同时使用系统词典和个人词典
cat README.md | hunspell -d en_US -p "$PROJECT_DICT" -l

# 项目词典通常放在版本控制中
echo ".hunspell_project" >> .gitignore  # 或不忽略,团队共享

3.6 格式化文本检查

Hunspell 可以理解多种标记语言,避免将标签/命令误认为拼写错误。

3.6.1 HTML 模式

# HTML 模式:忽略标签,只检查文本内容
hunspell -H page.html

# 示例 HTML
cat > /tmp/test.html << 'EOF'
<html>
<body>
  <h1>Welcom to My Site</h1>
  <p>This is a <strong>tesst</strong> page.</p>
  <p class="header">Anothr paragraph.</p>
</body>
</html>
EOF

hunspell -H -l -d en_US /tmp/test.html
# Welcom
# tesst
# Anothr

3.6.2 LaTeX 模式

# TeX/LaTeX 模式:忽略命令,只检查文本
hunspell -t paper.tex

# 示例 LaTeX
cat > /tmp/test.tex << 'EOF'
\documentclass{article}
\begin{document}
\title{An Introdution to Hunspell}
\maketitle

This documnet explains the basic usge of Hunspell.
We use \texttt{hunspell} for spel checking.

\end{document}
EOF

hunspell -t -l -d en_US /tmp/test.tex
# Introdution
# documnet
# usge
# spel

3.6.3 nroff/troff 模式

# man page 格式
hunspell -n manpage.1

3.6.4 模式对比

模式 参数 忽略内容 适用场景
纯文本 (默认) .txt 文件
HTML -H HTML 标签、实体 .html.htm
LaTeX -t LaTeX 命令、环境 .tex.sty
nroff -n troff 请求、宏 man pages
邮件 -e 邮件头 mbox 文件

3.7 词干提取与形态学

3.7.1 词干模式

# 提取词干
echo "running" | hunspell -s -d en_US
# running -> run

echo "wolves" | hunspell -s -d en_US
# wolves -> wolf

# 多词测试
echo "cats dogs running jumped" | hunspell -s -d en_US
# cats -> cat
# dogs -> dog
# running -> run
# jumped -> jump

3.7.2 形态学分析模式

# -m 输出详细形态信息
echo "running" | hunspell -m -d en_US
# running st:run po:verb ts:present_participle

# 解读:
# st:run          → 词干是 "run"
# po:verb         → 词性是动词
# ts:present_participle → 时态是现在分词
# -M 输出更详细的分解
echo "unhappiness" | hunspell -M -d en_US
# unhappiness: un+happi+ness

3.7.3 形态学信息对照表

缩写 含义 英文
st 词干 stem
po 词性 part of speech
ts 时态 tense
ps 人称 person
nu number
ca case
ge gender
mo 语气 mood
dv 派生 derivation

3.8 编码处理

3.8.1 默认编码行为

# Hunspell 自动检测编码(基于 .aff 文件中的 SET 指令)
# 大多数现代词典使用 UTF-8

# 手动指定输入编码
hunspell -i UTF-8 -d en_US file.txt
hunspell -i ISO-8859-1 -d de_DE file.txt

3.8.2 编码转换示例

# 如果文件编码与词典编码不匹配
file -i document.txt
# document.txt: text/plain; charset=iso-8859-1

# 转换后检查
iconv -f ISO-8859-1 -t UTF-8 document.txt | hunspell -d en_US -l

# 或者指定输入编码
hunspell -i ISO-8859-1 -d en_US document.txt

3.8.3 常见编码问题

# 问题:UTF-8 BOM 导致首行无法检查
# 解决:去掉 BOM
sed -i '1s/^\xEF\xBB\xBF//' file.txt

# 问题:混合编码文件
# 解决:统一转换
find . -name "*.txt" -exec sh -c '
    charset=$(file -bi "$1" | grep -oP "charset=\K[^ ]+")
    if [ "$charset" != "utf-8" ] && [ "$charset" != "us-ascii" ]; then
        iconv -f "$charset" -t UTF-8 "$1" -o "$1.utf8" && mv "$1.utf8" "$1"
        echo "转换: $1 ($charset → UTF-8)"
    fi
' _ {} \;

3.9 输出格式化与脚本集成

3.9.1 解析管道模式输出

#!/usr/bin/env python3
"""解析 hunspell -a 的输出,返回结构化结果"""
import subprocess
import re

def spell_check(text: str, dictionary: str = "en_US") -> list[dict]:
    """
    对文本进行拼写检查,返回结构化结果。
    
    返回格式:
    [
        {"word": "helo", "status": "misspelled", "suggestions": ["hello", ...]},
        {"word": "hello", "status": "correct", "suggestions": []},
        ...
    ]
    """
    result = subprocess.run(
        ["hunspell", "-a", "-d", dictionary],
        input=text, capture_output=True, text=True
    )
    
    entries = []
    for line in result.stdout.strip().split("\n"):
        if line.startswith("*"):
            # 正确的单词
            entries.append({"word": line[2:], "status": "correct", "suggestions": []})
        elif line.startswith("&"):
            # 有建议的错误
            match = re.match(r"& (\S+) \d+ \d+: (.+)", line)
            if match:
                word = match.group(1)
                suggestions = [s.strip() for s in match.group(2).split(",")]
                entries.append({"word": word, "status": "misspelled", "suggestions": suggestions})
        elif line.startswith("#"):
            # 无建议的错误
            match = re.match(r"# (\S+) \d+", line)
            if match:
                entries.append({"word": match.group(1), "status": "misspelled", "suggestions": []})
    
    return entries

# 使用
results = spell_check("This sentense has a typoo")
for r in results:
    if r["status"] == "misspelled":
        print(f"  ✗ '{r['word']}' → 建议: {', '.join(r['suggestions'][:5])}")
    else:
        print(f"  ✓ '{r['word']}'")

输出:

  ✓ 'This'
  ✗ 'sentense' → 建议: sentence, sentences
  ✓ 'has'
  ✓ 'a'
  ✗ 'typoo' → 建议: typo, types, type

3.9.2 JSON 输出包装

#!/bin/bash
# spellcheck_json.sh - 将 hunspell 输出转为 JSON
# 用法: ./spellcheck_json.sh <文件>

FILE="$1"
DICT="${2:-en_US}"

echo "["
first=true

while IFS= read -r word; do
    if [ -n "$word" ]; then
        if [ "$first" = true ]; then
            first=false
        else
            echo ","
        fi
        # 获取建议
        suggestions=$(echo "$word" | hunspell -a -d "$DICT" 2>/dev/null | \
            grep "^&" | sed 's/.*: //' | tr ',' '\n' | \
            sed 's/^ *//' | head -5 | \
            awk '{printf "\"%s\",", $0}' | sed 's/,$//')
        printf '  {"word": "%s", "suggestions": [%s]}' "$word" "$suggestions"
    fi
done < <(hunspell -l -d "$DICT" "$FILE" | sort -u)

echo ""
echo "]"

3.10 实用技巧

3.10.1 忽略大小写

# 使用 -C 参数忽略大小写(默认检查大小写)
echo "hello Hello HELLO" | hunspell -C -d en_US -l
# 无输出 → 全部正确

3.10.2 限制建议数量

# -L 限制每词建议数(默认 25)
echo "helo" | hunspell -a -d en_US -L 3
# & helo 3 0: hello, Helo, helot

3.10.3 结合 grep 过滤

# 只显示特定模式的错误
cat document.txt | hunspell -l | grep -E "^[A-Z]"  # 只看大写开头的
cat document.txt | hunspell -l | grep -E ".{20,}"  # 只看超长词

3.10.4 与 diff 结合

# 比较拼写检查前后的差异
hunspell -l file.txt > /tmp/errors_before.txt
# 编辑文件...
hunspell -l file.txt > /tmp/errors_after.txt
diff /tmp/errors_before.txt /tmp/errors_after.txt

3.10.5 拼写检查统计

#!/bin/bash
# spell_stats.sh - 拼写检查统计
FILE="$1"
DICT="${2:-en_US}"

TOTAL_WORDS=$(wc -w < "$FILE")
MISSPELLED=$(hunspell -l -d "$DICT" "$FILE" | wc -l)
UNIQUE_ERRORS=$(hunspell -l -d "$DICT" "$FILE" | sort -u | wc -l)
CORRECT=$((TOTAL_WORDS - MISSPELLED))

echo "=== 拼写检查统计 ==="
echo "文件:          $FILE"
echo "总词数:        $TOTAL_WORDS"
echo "拼写错误:      $MISSPELLED"
echo "唯一错误词:    $UNIQUE_ERRORS"
echo "正确率:        $(echo "scale=2; $CORRECT * 100 / $TOTAL_WORDS" | bc)%"
echo ""
echo "最常见的错误词:"
hunspell -l -d "$DICT" "$FILE" | sort | uniq -c | sort -rn | head -10

3.11 本章小结

模式 命令 适用场景
交互模式 hunspell -c file 手动更正单个文件
管道模式 hunspell -a / hunspell -l 脚本自动化
词干提取 hunspell -s NLP 预处理
形态分析 hunspell -m / -M 语言学研究
HTML 模式 hunspell -H Web 内容检查
LaTeX 模式 hunspell -t 学术论文检查

扩展阅读