c19e9fcebf
- 8 条 YAML 声明规则:页码/页眉页脚/目录点线/图片/HTML表格/散落标签/行尾空白/空行 - 防误伤设计:protect 正则 + 内容形态豁免 + OCR burst 检测 - md-clean single/batch CLI,JSON 清洗报告 - 18 个单元测试 Co-Authored-By: Claude <noreply@anthropic.com>
90 lines
3.2 KiB
Python
90 lines
3.2 KiB
Python
"""命令行入口。
|
||
|
||
用法:
|
||
md-clean single <input.md> [-o output.md] [--diff] [--rules rules.yaml]
|
||
md-clean batch <dir> [-o outdir] [--pattern "*.md"] [--report report.json]
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
import argparse
|
||
import json
|
||
import sys
|
||
from pathlib import Path
|
||
from typing import List, Optional
|
||
|
||
from cleaner.cleaner import MarkdownCleaner
|
||
from cleaner.rules import load_rules
|
||
|
||
|
||
def _build(path: Optional[Path]) -> MarkdownCleaner:
|
||
return MarkdownCleaner(rules=load_rules(path))
|
||
|
||
|
||
def cmd_single(args: argparse.Namespace) -> int:
|
||
cleaner = _build(args.rules)
|
||
src = Path(args.input)
|
||
raw = src.read_text(encoding="utf-8")
|
||
result = cleaner.clean_text(raw)
|
||
if args.output:
|
||
Path(args.output).parent.mkdir(parents=True, exist_ok=True)
|
||
Path(args.output).write_text(result.text, encoding="utf-8")
|
||
print(f"已写入 {args.output}")
|
||
if args.diff:
|
||
print(MarkdownCleaner.diff(raw, result.text))
|
||
print(json.dumps(result.stats, ensure_ascii=False, indent=2))
|
||
return 0
|
||
|
||
|
||
def cmd_batch(args: argparse.Namespace) -> int:
|
||
cleaner = _build(args.rules)
|
||
src_dir = Path(args.directory)
|
||
files = sorted(p for p in src_dir.rglob(args.pattern) if p.is_file())
|
||
if not files:
|
||
print(f"在 {src_dir} 下未找到匹配 {args.pattern} 的文件", file=sys.stderr)
|
||
return 1
|
||
out_dir = Path(args.output) if args.output else src_dir.parent / (src_dir.name + "_cleaned")
|
||
report = []
|
||
for f in files:
|
||
rel = f.relative_to(src_dir)
|
||
dst = out_dir / rel
|
||
result = cleaner.clean_file(f, dst)
|
||
report.append({"file": str(rel), "stats": result.stats})
|
||
hits = result.total_hits
|
||
print(f"[ok] {rel} 命中 {hits} 处")
|
||
if args.report:
|
||
Path(args.report).parent.mkdir(parents=True, exist_ok=True)
|
||
Path(args.report).write_text(
|
||
json.dumps({"files": report}, ensure_ascii=False, indent=2), encoding="utf-8"
|
||
)
|
||
print(f"报告已写入 {args.report}")
|
||
print(f"共清洗 {len(files)} 个文件 → {out_dir}")
|
||
return 0
|
||
|
||
|
||
def main(argv: Optional[List[str]] = None) -> int:
|
||
parser = argparse.ArgumentParser(prog="md-clean", description="政务文档 Markdown 清洗工具")
|
||
sub = parser.add_subparsers(dest="command", required=True)
|
||
|
||
p1 = sub.add_parser("single", help="清洗单个文件")
|
||
p1.add_argument("input", help="输入 .md 文件")
|
||
p1.add_argument("-o", "--output", help="输出路径(缺省打印统计不写文件)")
|
||
p1.add_argument("--diff", action="store_true", help="打印 unified diff")
|
||
p1.add_argument("--rules", type=Path, help="规则 YAML 路径")
|
||
|
||
p2 = sub.add_parser("batch", help="批量清洗目录(递归)")
|
||
p2.add_argument("directory", help="输入目录")
|
||
p2.add_argument("-o", "--output", help="输出目录(缺省 <dir>_cleaned)")
|
||
p2.add_argument("--pattern", default="*.md", help="文件 glob(默认 *.md)")
|
||
p2.add_argument("--report", help="清洗报告 JSON 输出路径")
|
||
p2.add_argument("--rules", type=Path, help="规则 YAML 路径")
|
||
|
||
args = parser.parse_args(argv)
|
||
if args.command == "single":
|
||
return cmd_single(args)
|
||
return cmd_batch(args)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
sys.exit(main())
|