japanese/README_cleaner.md
panli ef3df73166 refactor: 三层架构重构 + 配置文件 + 项目目录整理
清洗管线重构为严格三层架构:
- tango_analyser.py(底层:单词分析)
- task_processor.py(中层:文件 I/O、桶管理)
- workflow.py(顶层:状态机、任务推进)
- 移除旧的 batch_processor.py

新增配置文件系统:
- config.py:TOML 配置,相对路径相对配置文件目录解析
- 查找优先级 --config > cwd > 项目根 > ~ > 默认值
- count=None 语义为处理到文件末尾

项目目录整理:
- 根脚本归档到 scripts/analysis 与 scripts/legacy
- 文档归档到 docs/{design,history,analysis}
- 临时报告移到 reports/(已 gitignore)

文档质量:
- 新增 .markdownlint.json 与 scripts/mdlint.cmd
- 修复全部 14 个 md 文件的 markdownlint 警告

测试:74 passed(8 cleaner + 31 workflow + 6 tango + 15 validator + 14 config)
2026-08-19 19:40:02 +08:00

12 KiB
Raw Permalink Blame History

Japanese Cleaner - 日语词表清洗工具

工程化的日语词表清洗流水线,自动化处理汉字-假名-拼音对齐。采用三层架构 + 任务化 清晰的职责分层,每次清洗是一个跨会话、有状态、可并存的任务。

完整协作规范见 WORKFLOW.md

架构设计

三层职责分离(自底向上):

模块 职责 对外接口
底层 · 单词级 tango_analyser.py 接收单个词条 (kanji, kana),输出 AnalysisResult(格式化行 + 状态分类)。封装 Classifier / Aligner / PinyinMaker不碰文件、不知道"桶"。 TangoAnalyser.analyze()
中间层 · 文件级 task_processor.py 持有 Task因此知道所有文件路径读源文件/review 文件 → 调底层 → 按状态分流写入桶文件;合并单批到权威库。只搬文件,不改任务状态 TaskProcessor.process_source() / .process_review() / .merge_final()
工作流层 · 编排级 workflow.py 给定任务判断走到哪一步、下一步做什么,唯一接口 run() 推进任务;更新任务状态机 created → reviewing/ready → merged CleanerWorkflow.run()

任务模型

  • Task / TaskConfig / TaskState — 配置 + 状态机 + 独立目录
  • TaskManager — 任务 CRUD多任务并存

设计原则

  • 底层不知道文件/桶,只返回状态枚举(AnalysisStatus
  • 中间层持有路径、负责 I/O但不决策"该做什么"
  • 工作流层只做决策/编排,委托中间层执行文件操作

功能特性

  • 三层架构:职责清晰,底层可独立测试,工作流可编排复杂逻辑
  • 配置文件管理TOML 格式,支持相对/绝对路径,多项目友好
  • 任务化:每次清洗是独立任务(独立配置 + 独立临时文件 + 状态机),多任务可并存
  • 两层分离:单批临时工作区 / 最终只增去重的权威库
  • 数据源只读:处理时不修改原文件,支持任意切片(起始行 + 条数)
  • 严格校验:输入输出条数自动校验
  • 半自动协作:自动分流 + 人工 review + 改代码重跑
  • 工作流推进run() 一键推进,能自动处理就处理,需人工就提示
  • 单元测试73 个测试全覆盖(底层单词分析 / 文件处理 / 工作流编排 / 配置管理)

数据目录布局

data/
├── db/                          # 权威成品库(只增不删 + 去重)
│   ├── vocabulary.txt           # 所有批次累积的成品
│   └── skipped.txt              # 所有批次累积的跳过项
├── sources/                     # 原始数据源(只读)
│   └── xinbiaori_1.txt
└── backup/                      # 备份
    └── *.backup.txt

tasks/
└── {task_id}/                   # 每个任务独立目录
    ├── task.json                # 任务配置 + 状态
    ├── auto_done.txt            # 单批结果
    ├── skip.txt
    └── review_*.txt             # 待确认桶pinyin/split/verb/special

入口方式

本项目的清洗流程需要人工介入review 循环:改字典/规则 → 重跑),因此 推荐用测试驱动协作(见 tests/test_cleaner_workflow.py 命令行只是便捷入口。

三种等价的命令行入口:

jclean <cmd> ...                          # 安装后的 console 命令(推荐)
python -m pl_japanese.cleaner.cli <cmd> ... # 模块调用(无需 console 入口)
python scripts/clean.py <cmd> ...          # 兼容薄壳(未安装包时)

安装(开发模式,注册 jclean 命令):

pip install -e .

配置文件

支持 TOML 格式配置文件,路径可以是相对路径(相对配置文件所在目录)或绝对路径。

生成示例配置

jclean init-config
# 生成 jclean.toml编辑后自动生效

配置文件示例

# jclean.toml

[paths]
# 任务根目录(存放所有任务的独立目录)
tasks_root = "tasks"

# 权威库(所有任务最终合并的目标)
vocabulary = "data/db/vocabulary.txt"
skipped = "data/db/skipped.txt"

# 数据源目录(可选)
sources_dir = "data/sources"

[defaults]
# 创建任务时的默认值
start_line = 1
count = 300

# 是否在合并前自动备份权威库
backup_before_merge = true
backup_dir = "data/backup"

[logging]
# 日志级别DEBUG / INFO / WARNING / ERROR
level = "INFO"

配置文件查找顺序

  1. 命令行参数 --config /path/to/config.toml(最高优先级)
  2. 当前目录 ./jclean.toml./.jclean.toml
  3. 向上查找项目根(遇到 .git 停止)
  4. 用户主目录 ~/.jclean.toml
  5. 硬编码默认值

路径解析规则

  • 绝对路径:直接使用
  • 相对路径:相对配置文件所在目录

示例(配置文件在 /home/user/project/jclean.toml

[paths]
tasks_root = "tasks"                    # → /home/user/project/tasks
vocabulary = "/data/global/vocab.txt"   # → /data/global/vocab.txt绝对
sources_dir = "../shared/sources"       # → /home/user/shared/sources

查看当前配置

jclean show-config
# 显示当前生效的配置(包含解析后的绝对路径)

优先级

命令行参数 > 配置文件 > 默认值

# 配置文件中 tasks_root = "tasks"
# 命令行参数覆盖配置文件
jclean --tasks-root /custom/tasks create batch1 --source ...

快速开始

CLI 方式(极简命令)

# 1. 创建任务(数据源只读,可指定处理范围)
jclean create batch1 --source data/sources/xinbiaori_1.txt --start 1 --count 300

# 2. 工作流推进(自动判断下一步,能做就做,需人工就提示)
jclean run batch1

# 3. 如果有 review 待确认:人工修正字典/规则后,重跑指定桶
jclean run batch1 --bucket pinyin

# 4. 继续推进review 清零后自动合并)
jclean run batch1

# 5. 完成!

# 其他命令
jclean list             # 列举所有任务
jclean status batch1    # 查看任务状态
jclean clear batch1     # 清空单批文件

代码调用(三层 API

工作流层(推荐,高层抽象)

from pl_japanese.cleaner import TaskManager, CleanerWorkflow

tm = TaskManager()
task = tm.create_task(
    task_id='batch1',
    source='data/sources/xinbiaori_1.txt',
    start_line=1,
    count=300,
)

wf = CleanerWorkflow(task)

# 自动推进
result = wf.run()
print(result['action'])    # 'processed' / 'need_human' / 'completed'
print(result['status'])    # 'reviewing' / 'ready' / 'merged'
print(result['message'])   # 处理结果说明

# 如果需要人工介入
if result['action'] == 'need_human':
    print(result['review'])  # 待确认的 review 桶摘要
    # 人工修正字典/规则后,重跑指定桶
    wf.processor.process_review('pinyin')
    result = wf.run()  # 继续推进

# 循环推进直到完成
while result['action'] != 'completed':
    result = wf.run()
    if result['action'] == 'need_human':
        break

中间层(文件操作,精细控制)

from pl_japanese.cleaner import TaskManager, TaskProcessor

tm = TaskManager()
task = tm.load_task('batch1')
proc = TaskProcessor(task)

# 处理源文件
result = proc.process_source()
print(result['buckets'])      # 各桶条数
print(result['review_total']) # 需 review 的总数

# 重跑某个 review 桶
result = proc.process_review('pinyin')

# 合并dry-run 校验)
result = proc.merge_final(dry_run=True)

# 查询当前状态
print(proc.snapshot_counts())  # 各单批桶当前条数
print(proc.review_total())     # review 总数
print(proc.final_counts())     # 权威库条数

底层(单词分析,测试/调试用)

from pl_japanese.cleaner import TangoAnalyser, AnalysisStatus

analyser = TangoAnalyser()

# 分析单个词条
result = analyser.analyze("日本人", "にほんじん")
print(result.status)          # AnalysisStatus.SUCCESS
print(result.formatted_line)  # "日|本|人:に|ほん|じん:ri|ben|ren"
print(result.is_success)      # True
print(result.needs_review)    # False

# 需人工确认的词
result = analyser.analyze("女将", "おかみ")
print(result.status)          # AnalysisStatus.SPLIT_FAILED
print(result.needs_review)    # True

核心概念

状态分类(底层)

AnalysisStatus 枚举(底层单词分析结果):

状态 含义 是否需 review
SUCCESS 成功处理,格式化行可直接采用
SKIP 无汉字等,跳过不进成品库
POLYPHONE 含多音字/多解,拼音需人工确认
SPLIT_FAILED 假名无法与汉字对齐分割
VERB_FORM 动词/敬语,需确认形式
SPECIAL_CASE 含字母/片假名/格式异常

状态机(工作流层)

任务状态流转:

created
  ↓ run() → process_source
reviewing (有 review_* 待确认)
  ↓ 人工改代码/字典 + process_review → review 清零
  ↓ run() → 检测清零
ready (可合并)
  ↓ run() → merge_final
merged (完成)
  ↓ run()
completed (终态)

单批桶(中间层文件分类)

桶名 对应状态 含义
auto_done.txt SUCCESS 自动处理成功,待合并进 vocabulary.txt
skip.txt SKIP 跳过(无汉字等),待合并进 skipped.txt
review_pinyin.txt POLYPHONE 多音字待确认
review_split.txt SPLIT_FAILED 分割失败待人工
review_verb.txt VERB_FORM 动词形式待确认
review_special.txt SPECIAL_CASE 特殊情况待判断

工作流 run() 返回

CleanerWorkflow.run() 返回 dict关键字段

字段 含义
action processed(推进了)/ need_human(需人工)/ completed(完成)/ empty(无内容)
status 推进后的任务状态(created / reviewing / ready / merged
message 人类可读说明
review need_human 时)待确认的 review 桶摘要 {bucket: {count, sample}}
process processed 时)处理结果统计
merge processed 且合并时)合并结果统计

分类规则

核心规则详见 src/pl_japanese/cleaner/classifier.py

汉字分词(自动)

  • 每个汉字单独一段
  • ~(通配符)单独一段,匹配任意长假名
  • 其余非汉字连续合并成一段

拼音生成

  • 汉字:查 WORD_OVERRIDE 全词覆写 → 查 KANA_HINT 假名提示 → pypinyin
  • 多音字检测pypinyin 返回多个候选 → 标记 POLYPHONE

动词处理

  • 假名以 う段 结尾 / 含 ~ 标记 / 假名末有 "ます/ません/ました" → 判定为动词
  • 去掉送り仮名(活用后缀)后处理

跳过规则

  • 无汉字 → SKIP
  • 纯片假名/字母/符号 → SKIP

字典路径(多音字覆写):

  • WORD_OVERRIDE:全词精确匹配(优先级最高)
  • KANA_HINT(kanji, kana_prefix) → pinyin用于区分假名提示多音字

测试

# 运行所有测试60 个)
pytest tests/

# 只测工作流31 个)
pytest tests/test_cleaner_workflow.py -v

# 只测底层分析8 个)
pytest tests/test_cleaner.py -v

测试覆盖:

  • 底层单词分析状态分类、格式输出、needs_review 逻辑
  • 中间层文件处理条数铁律、追加模式、去重、格式校验、review 重跑
  • 工作流编排状态机推进、人工介入门禁、review 清零自动转 ready、合并授权
  • 任务管理CRUD、多任务隔离、持久化

版本历史

  • v0.3.0 (2025-01):三层架构重构 + 配置文件管理
    • 三层职责清晰分离(底层单词分析 / 中间层文件处理 / 工作流编排)
    • 新增 CleanerWorkflow.run() 工作流推进
    • CLI 精简5 个命令,run 统一推进)
    • TOML 配置文件支持(相对/绝对路径)
    • 73 个测试全覆盖
  • v0.2.0 (2025-01):任务化架构,多任务并存,状态机管理
  • v0.1.0 (2024):初版单批流水线

许可

MIT