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

389 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Japanese Cleaner - 日语词表清洗工具
工程化的日语词表清洗流水线,自动化处理汉字-假名-拼音对齐。采用**三层架构 + 任务化**
清晰的职责分层,每次清洗是一个跨会话、有状态、可并存的任务。
> 完整协作规范见 [`WORKFLOW.md`](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 个测试全覆盖(底层单词分析 / 文件处理 / 工作流编排 / 配置管理)
## 数据目录布局
```text
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`](tests/test_cleaner_workflow.py)
命令行只是便捷入口。
三种等价的命令行入口:
```bash
jclean <cmd> ... # 安装后的 console 命令(推荐)
python -m pl_japanese.cleaner.cli <cmd> ... # 模块调用(无需 console 入口)
python scripts/clean.py <cmd> ... # 兼容薄壳(未安装包时)
```
安装(开发模式,注册 `jclean` 命令):
```bash
pip install -e .
```
## 配置文件
支持 TOML 格式配置文件,路径可以是相对路径(相对配置文件所在目录)或绝对路径。
### 生成示例配置
```bash
jclean init-config
# 生成 jclean.toml编辑后自动生效
```
### 配置文件示例
```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`
```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
```
### 查看当前配置
```bash
jclean show-config
# 显示当前生效的配置(包含解析后的绝对路径)
```
### 优先级
命令行参数 > 配置文件 > 默认值
```bash
# 配置文件中 tasks_root = "tasks"
# 命令行参数覆盖配置文件
jclean --tasks-root /custom/tasks create batch1 --source ...
```
## 快速开始
### CLI 方式(极简命令)
```bash
# 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
#### 工作流层(推荐,高层抽象)
```python
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
```
#### 中间层(文件操作,精细控制)
```python
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()) # 权威库条数
```
#### 底层(单词分析,测试/调试用)
```python
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` | 含字母/片假名/格式异常 | ✅ |
### 状态机(工作流层)
任务状态流转:
```text
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`](src/pl_japanese/cleaner/classifier.py)。
**汉字分词(自动)**
- 每个汉字单独一段
- `~`(通配符)单独一段,匹配任意长假名
- 其余非汉字连续合并成一段
**拼音生成**
- 汉字:查 `WORD_OVERRIDE` 全词覆写 → 查 `KANA_HINT` 假名提示 → pypinyin
- 多音字检测pypinyin 返回多个候选 → 标记 `POLYPHONE`
**动词处理**
- 假名以 `う段` 结尾 / 含 `~` 标记 / 假名末有 "ます/ません/ました" → 判定为动词
- 去掉送り仮名(活用后缀)后处理
**跳过规则**
- 无汉字 → `SKIP`
- 纯片假名/字母/符号 → `SKIP`
**字典路径**(多音字覆写):
- `WORD_OVERRIDE`:全词精确匹配(优先级最高)
- `KANA_HINT``(kanji, kana_prefix)` → pinyin用于区分假名提示多音字
## 测试
```bash
# 运行所有测试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