|
|
|
|
|
|
| import argparse
|
| import json
|
| import os
|
| import re
|
| import sys
|
| from pathlib import Path
|
|
|
| def process_file(path: Path, pattern: re.Pattern, dry_run: bool, backup: bool) -> tuple[bool, str]:
|
| """
|
| Return (changed, message)
|
| """
|
| m = pattern.search(path.name)
|
| if not m:
|
| return (False, f"跳过(文件名不匹配):{path.name}")
|
|
|
| number_str = m.group(1)
|
|
|
| try:
|
| text = path.read_text(encoding="utf-8")
|
| except UnicodeDecodeError:
|
|
|
| text = path.read_text(encoding="utf-8-sig", errors="replace")
|
|
|
| try:
|
| data = json.loads(text)
|
| except Exception as e:
|
| return (False, f"错误(JSON 解析失败):{path.name} -> {e}")
|
|
|
| if not isinstance(data, dict):
|
| return (False, f"跳过(JSON 顶层不是对象):{path.name}")
|
|
|
| old_number = data.get("Number", None)
|
| old_source = data.get("Source", None)
|
| old_source = data.get("Type", None)
|
|
|
| data["Number"] = str(number_str)
|
| data["Source"] = "Vchart"
|
| data["Type"] = "pie"
|
|
|
|
|
| changed = (old_number != data["Number"]) or (old_source != data["Source"])
|
|
|
| if dry_run:
|
| return (changed, f"[DRY] {path.name}: Number {old_number!r} -> {data['Number']!r}, Source {old_source!r} -> 'Vchart'")
|
|
|
| if changed and backup:
|
| bak = path.with_suffix(path.suffix + ".bak")
|
| if not bak.exists():
|
| bak.write_text(text, encoding="utf-8")
|
|
|
| if changed:
|
| path.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding="utf-8")
|
| return (True, f"已修改:{path.name} -> Number='{number_str}', Source='Vchart'")
|
| else:
|
| return (False, f"无变化:{path.name}(已是目标值)")
|
|
|
| def iter_json_files(folder: Path, recursive: bool):
|
| if recursive:
|
| yield from folder.rglob("*.json")
|
| else:
|
| yield from folder.glob("*.json")
|
|
|
| def main():
|
| ap = argparse.ArgumentParser(description="批量修改 JSON: Number=文件名中的数字字符串; Source=Vchart")
|
| ap.add_argument("dir", help="要处理的文件夹路径")
|
| ap.add_argument("--recursive", action="store_true", help="递归处理子文件夹")
|
| ap.add_argument("--dry-run", action="store_true", help="只打印不写入")
|
| ap.add_argument("--backup", action="store_true", help="修改前生成 .bak(仅第一次)")
|
| ap.add_argument("--pattern", default=r"chart_(\d+)_", help=r"从文件名提取数字的正则,默认: chart_(\d+)_")
|
| args = ap.parse_args()
|
|
|
| folder = Path(args.dir)
|
| if not folder.exists() or not folder.is_dir():
|
| print(f"目录不存在或不是文件夹:{folder}", file=sys.stderr)
|
| return 2
|
|
|
| pattern = re.compile(args.pattern)
|
|
|
| total = 0
|
| changed_count = 0
|
| skipped_or_nochange = 0
|
|
|
| for p in iter_json_files(folder, args.recursive):
|
| total += 1
|
| changed, msg = process_file(p, pattern, args.dry_run, args.backup)
|
| print(msg)
|
| if changed:
|
| changed_count += 1
|
| else:
|
| skipped_or_nochange += 1
|
|
|
| print("\n==== 统计 ====")
|
| print(f"总计扫描: {total}")
|
| print(f"发生修改: {changed_count}")
|
| print(f"跳过/无变化/错误: {skipped_or_nochange}")
|
| return 0
|
|
|
| if __name__ == "__main__":
|
| raise SystemExit(main())
|
|
|