首次提交

This commit is contained in:
2026-09-28 16:09:31 +08:00
commit 4a6839319a
71 changed files with 12144 additions and 0 deletions

111
tools/检查srt质量.py Normal file
View File

@@ -0,0 +1,111 @@
# -*- coding: utf-8 -*-
"""
扫描 SRT 文件, 报告字幕质量指标 + 抽样, 帮你快速判断OCR字幕好不好。
纯标准库。
用法:
python3 tools/检查srt质量.py ./srt # 扫目录下所有 .srt
python3 tools/检查srt质量.py a.srt b.srt # 扫指定文件
python3 tools/检查srt质量.py ./srt --sample 8 # 多抽几条看
"""
import argparse
import glob
import os
import re
CJK = re.compile(r'[一-鿿]')
def parse_srt(path):
"""返回 [(idx, start, end, text), ...]"""
try:
raw = open(path, encoding='utf-8', errors='ignore').read()
except OSError:
return []
blocks = re.split(r'\n\s*\n', raw.strip())
out = []
for b in blocks:
lines = [x for x in b.splitlines() if x.strip()]
if len(lines) < 2:
continue
m = re.search(r'(\d+):(\d+):(\d+)[,.](\d+)\s*-->\s*(\d+):(\d+):(\d+)[,.](\d+)', b)
if not m:
continue
g = list(map(int, m.groups()))
st = g[0]*3600 + g[1]*60 + g[2] + g[3]/1000.0
en = g[4]*3600 + g[5]*60 + g[6] + g[7]/1000.0
ti = next((i for i, l in enumerate(lines) if '-->' in l), 0)
text = ' '.join(lines[ti+1:]).strip()
out.append((st, en, text))
return out
def has_self_repeat(s, minlen=4):
"""检测整条里前半段==后半段这种自我重复(如 AABB → AB 重复)。"""
n = len(s)
if n < minlen * 2:
return False
h = n // 2
return s[:h] == s[h:2*h] and len(s[:h]) >= minlen
def scan(paths, sample):
files = []
for p in paths:
if os.path.isdir(p):
files += glob.glob(os.path.join(p, '**', '*.srt'), recursive=True)
elif p.endswith('.srt'):
files.append(p)
if not files:
print("没找到 .srt")
return
tot_e = empty = dup = selfrep = tooshort = lowcjk = badtime = 0
chars = 0
samples = []
for f in files:
subs = parse_srt(f)
prev = None
for st, en, text in subs:
tot_e += 1
chars += len(text)
if not text:
empty += 1
if prev is not None and text and text == prev:
dup += 1
if has_self_repeat(text):
selfrep += 1
if text and len(text) <= 1:
tooshort += 1
if text and len(CJK.findall(text)) < len(text) * 0.3 and len(text) > 4:
lowcjk += 1 # 中文占比过低 → 可能乱码/纯符号
if en <= st or (en - st) > 30:
badtime += 1
prev = text
if subs and len(samples) < sample:
mid = len(subs) // 2
for s in subs[mid:mid+2]:
samples.append((os.path.basename(f), s))
print("=" * 58)
print(f"SRT 文件 {len(files)} 个 | 字幕条目 {tot_e} 条 | 平均 {chars/max(tot_e,1):.1f} 字/条")
print("-" * 58)
def pct(x): return f"{x} ({x/max(tot_e,1)*100:.1f}%)"
print(f" 空条目: {pct(empty)} <- 应≈0")
print(f" 连续重复(同上条): {pct(dup)} <- 高=去重没做好")
print(f" 自我重复(AABB): {pct(selfrep)} <- 高=自重复bug")
print(f" 单字条目: {pct(tooshort)}")
print(f" 低中文占比(疑乱码):{pct(lowcjk)} <- 高=OCR乱/纯符号")
print(f" 时间轴异常: {pct(badtime)} <- 重叠/0时长/超30s")
print("=" * 58)
print("抽样字幕:")
for fn, (st, en, text) in samples[:sample]:
print(f" [{st:6.1f}-{en:6.1f}] {text[:50]} ({fn})")
if __name__ == '__main__':
ap = argparse.ArgumentParser()
ap.add_argument('paths', nargs='+')
ap.add_argument('--sample', type=int, default=6)
a = ap.parse_args()
scan(a.paths, a.sample)