移除FP YARN中的非放出文本

This commit is contained in:
Ovid
2026-04-25 19:27:21 +08:00
parent 8ab7441321
commit fbac02f641
23 changed files with 8984 additions and 8806 deletions
+209
View File
@@ -0,0 +1,209 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Yarn Spinner 文件 line tag 去重工具
用法:
python dedup_yarn_tags.py <文件路径> --from-node <节点名>
python dedup_yarn_tags.py <文件路径> --from-line <行号>
python dedup_yarn_tags.py <目录路径> --scan-all [--fix]
示例:
python dedup_yarn_tags.py Assets/Resources/Yarn/FP_Day1_mid/Day1_mid.yarn --from-node 地铁ver4
python dedup_yarn_tags.py Assets/Resources/Yarn/Fiction_Day1_begin/Fiction_Day1_begin.yarn --from-line 535 --fix
python dedup_yarn_tags.py Assets/Resources/Yarn/ --scan-all
"""
import argparse
import os
import re
import sys
def extract_line_tags(lines):
"""从行列表中提取所有 line tag,返回 (行索引, tag) 列表"""
tags = []
pattern = re.compile(r'#line:[0-9a-fA-F]+')
for idx, line in enumerate(lines):
match = pattern.search(line)
if match:
tags.append((idx, match.group(), match.start(), match.end()))
return tags
def find_node_start_line(lines, node_title):
"""根据节点 title 找到该节点开始的行索引(0-based)"""
title_pattern = re.compile(r'^title:\s*' + re.escape(node_title) + r'\s*$')
for idx, line in enumerate(lines):
if title_pattern.match(line):
# 找到 title 行,返回这一行(或返回 header 结束后的行)
# 通常用户说"从某个节点开始",指的是该节点内容开始
# 我们返回 title 行所在的位置即可,重复检测会自然跳过前面的 tag
return idx
return None
def process_file(file_path, start_line_1based=None, node_title=None, fix=False, verbose=True):
"""
处理单个 Yarn 文件
返回 (修改行数, 总重复数, 是否成功)
start_line_1based: 1-based 行号,None 表示从头开始
"""
if not os.path.exists(file_path):
if verbose:
print(f"[错误] 文件不存在: {file_path}")
return 0, 0, False
with open(file_path, 'r', encoding='utf-8') as f:
lines = f.readlines()
tags = extract_line_tags(lines)
if not tags:
if verbose:
print(f"[信息] 未找到任何 line tag: {file_path}")
return 0, 0, True
# 确定起始行索引(0-based
start_idx = 0
if node_title:
found = find_node_start_line(lines, node_title)
if found is None:
if verbose:
print(f"[错误] 未找到节点 '{node_title}' in {file_path}")
return 0, 0, False
start_idx = found
if verbose:
print(f"[信息] 定位到节点 '{node_title}' 在第 {found + 1}")
elif start_line_1based:
start_idx = start_line_1based - 1
if start_idx < 0:
start_idx = 0
if verbose:
print(f"[信息] 从第 {start_line_1based} 行开始处理")
# 收集 start_idx 之前的所有 tag
seen_tags = set()
for idx, tag, _, _ in tags:
if idx < start_idx:
seen_tags.add(tag)
# 检测 start_idx 之后的重复
duplicates = []
for idx, tag, start_pos, end_pos in tags:
if idx >= start_idx and tag in seen_tags:
duplicates.append((idx, tag, start_pos, end_pos))
elif idx >= start_idx:
# 即使在处理范围内,也要记录已见,防止范围内自身重复
seen_tags.add(tag)
if not duplicates:
if verbose:
print(f"[信息] 未发现重复 line tag: {file_path}")
return 0, 0, True
if verbose:
print(f"[发现] 找到 {len(duplicates)} 个重复 line tag:")
for idx, tag, _, _ in duplicates:
line_content = lines[idx].rstrip('\n')
# 截断过长行
display = line_content[:80] + "..." if len(line_content) > 80 else line_content
print(f"{idx + 1} 行: {tag} | {display}")
if not fix:
if verbose:
print(f"[提示] 使用 --fix 参数执行修改")
return 0, len(duplicates), True
# 执行修改:从后往前替换,避免位置偏移
modified_count = 0
for idx, tag, _, _ in sorted(duplicates, key=lambda x: x[0], reverse=True):
line = lines[idx]
new_line = line.replace(tag, '', 1).rstrip()
if not new_line.endswith('\n'):
new_line += '\n'
if new_line != line:
lines[idx] = new_line
modified_count += 1
with open(file_path, 'w', encoding='utf-8') as f:
f.writelines(lines)
if verbose:
print(f"[完成] 已修改 {modified_count} 行,移除 {len(duplicates)} 个重复 tag")
return modified_count, len(duplicates), True
def scan_directory(dir_path, fix=False):
"""扫描目录下所有 .yarn 文件"""
if not os.path.isdir(dir_path):
print(f"[错误] 目录不存在: {dir_path}")
return
yarn_files = []
for root, _, files in os.walk(dir_path):
for f in files:
if f.endswith('.yarn'):
yarn_files.append(os.path.join(root, f))
if not yarn_files:
print(f"[信息] 未找到 .yarn 文件: {dir_path}")
return
print(f"[信息] 共找到 {len(yarn_files)} 个 .yarn 文件")
total_duplicates = 0
total_modified = 0
for fp in yarn_files:
print(f"\n[扫描] {fp}")
mod, dup, ok = process_file(fp, start_line_1based=1, fix=fix, verbose=True)
if ok:
total_modified += mod
total_duplicates += dup
print(f"\n[汇总] 处理 {len(yarn_files)} 个文件,共发现 {total_duplicates} 个重复 tag,修改 {total_modified}")
def main():
parser = argparse.ArgumentParser(
description='Yarn Spinner line tag 去重工具',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog='''
示例:
%(prog)s file.yarn --from-node 地铁ver4 --dry-run
%(prog)s file.yarn --from-line 535 --fix
%(prog)s dir/ --scan-all --fix
'''
)
parser.add_argument('path', help='Yarn 文件或目录路径')
parser.add_argument('--from-node', help='从指定节点 title 开始检测重复')
parser.add_argument('--from-line', type=int, help='从指定 1-based 行号开始检测重复')
parser.add_argument('--scan-all', action='store_true', help='扫描目录下所有 .yarn 文件(从第1行开始)')
parser.add_argument('--fix', action='store_true', help='执行修改(默认仅预览)')
args = parser.parse_args()
target_path = os.path.abspath(args.path)
if args.scan_all:
scan_directory(target_path, fix=args.fix)
elif os.path.isfile(target_path):
if args.from_node and args.from_line:
print("[错误] --from-node 和 --from-line 不能同时使用")
sys.exit(1)
mod, dup, ok = process_file(
target_path,
start_line_1based=args.from_line,
node_title=args.from_node,
fix=args.fix,
verbose=True
)
if not ok:
sys.exit(1)
else:
print(f"[错误] 路径既不是文件也不是目录(或未提供 --scan-all: {target_path}")
sys.exit(1)
if __name__ == '__main__':
main()