项目文件夹

文件
wehub-resource-sync 39a086b41b
Build Windows CPU / build (push) Has been cancelled
Build Windows CUDA 10.2 / build (push) Has been cancelled
Build Windows CUDA 11.8 / build (push) Has been cancelled
Build Windows CUDA 12.6 / build (push) Has been cancelled
Build Windows DirectML / build (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:08:08 +08:00

221 行
8.9 KiB
Python

# -*- coding: UTF-8 -*-
"""
@author: eritpchy
@file : reformat.py
@time : 2021/12/17 15:43
@desc : 将连起来的英文单词切分
"""
import json
import os
import sys
import traceback
import pysrt
import wordsegment as ws
import re
def execute(path, lang='en'):
try:
print(f"Starting to process subtitle file: {path}, language: {lang}")
# fix "RecursionError: maximum recursion depth exceeded in comparison" in wordsegment.segment call
if sys.getrecursionlimit() < 100000:
sys.setrecursionlimit(100000)
# Check if file exists
if not os.path.exists(path):
print(f"Error: Subtitle file does not exist: {path}")
return False
wordsegment = ws.Segmenter()
wordsegment.load()
try:
subs = pysrt.open(path)
except Exception as e:
print(f"Error: Failed to open subtitle file: {str(e)}")
print(traceback.format_exc())
return False
verb_forms = ["I'm", "you're", "he's", "she's", "we're", "it's", "isn't", "aren't", "they're", "there's", "wasn't",
"weren't", "I've", "you've", "we've", "they've", "hasn't", "haven't", "I'd", "you'd", "he'd", "she'd",
"it'd", "we'd", "they'd", "doesn't", "don't", "didn't", "I'll", "you'll", "he'll", "she'll", "we'll",
"they'll", "there'll", "there'd", "can't", "couldn't", "daren't", "hadn't", "mightn't", "mustn't",
"needn't", "oughtn't", "shan't", "shouldn't", "usedn't", "won't", "wouldn't", "that's", "what's", "it'll"]
verb_form_map = {}
typo_map_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'configs', 'typoMap.json')
try:
with open(typo_map_path, 'r', encoding='utf-8') as load_f:
typo_map = json.load(load_f)
except Exception as e:
print(f"Error: Failed to load typoMap.json: {str(e)}")
print(traceback.format_exc())
typo_map = {}
for verb in verb_forms:
verb_form_map[verb.replace("'", "").lower()] = verb
def format_seg_list(seg_list):
new_seg = []
for seg in seg_list:
if seg in verb_form_map:
new_seg.append([seg, verb_form_map[seg]])
else:
new_seg.append([seg])
return new_seg
def typo_fix(text):
for k, v in typo_map.items():
try:
text = re.sub(re.compile(k, re.I), v, text)
except Exception as e:
print(f"Warning: Regex replacement failed: {k} -> {v}, error: {str(e)}")
return text
# 逆向过滤seg
def remove_invalid_segment(seg, text):
try:
seg_len = len(seg)
span = None
new_seg = []
for i in range(seg_len - 1, -1, -1):
s = seg[i]
if len(s) > 1:
regex = re.compile(f"({s[0]}|{s[1]})", re.I)
else:
regex = re.compile(f"({s[0]})", re.I)
try:
ss = [(i) for i in re.finditer(regex, text)][-1]
except IndexError:
ss = None
if ss is None:
continue
text = text[:ss.span()[0]]
if span is None:
span = ss.span()
new_seg.append(s)
continue
if span > ss.span():
new_seg.append(s)
span = ss.span()
return list(reversed(new_seg))
except Exception as e:
print(f"Error: remove_invalid_segment failed: {str(e)}")
print(traceback.format_exc())
return []
modified_count = 0
for index, sub in enumerate(subs):
try:
if not hasattr(sub, 'text') or not sub.text:
continue
original_text = sub.text
sub.text = typo_fix(sub.text)
# Limit text length to avoid processing too long text
if len(sub.text) > 1000:
print(f"Warning: Subtitle text too long, skipping word segmentation: {len(sub.text)} characters")
continue
try:
seg = wordsegment.segment(sub.text)
if len(seg) == 1:
seg = wordsegment.segment(re.sub(re.compile(f"(\ni)([^\\s])", re.I), "\\1 \\2", sub.text))
except Exception as e:
print(f"Error: Word segmentation failed: {str(e)}")
print(traceback.format_exc())
continue
seg = format_seg_list(seg)
# 替换中文前的多个空格成单个空格, 避免中英文分行出错
sub.text = re.sub(' +([\\u4e00-\\u9fa5])', ' \\1', sub.text)
# 中英文分行
if lang in ["ch", "ch_tra"]:
sub.text = sub.text.replace(" ", "\n")
lines = []
remain = sub.text
seg = remove_invalid_segment(seg, sub.text)
seg_len = len(seg)
for i in range(0, seg_len):
s = seg[i]
if len(s) > 1:
regex = re.compile(f"(.*?)({s[0]}|{s[1]})", re.I)
else:
regex = re.compile(f"(.*?)({s[0]})", re.I)
ss = re.search(regex, remain)
if ss is None:
if i == seg_len - 1:
lines.append(remain.strip())
continue
lines.append(remain[:ss.span()[1]].strip())
remain = remain[ss.span()[1]:].strip()
if i == seg_len - 1:
lines.append(remain)
if seg_len > 0:
ss = " ".join(lines)
else:
ss = remain
# again
ss = typo_fix(ss)
# 非大写字母的大写字母前加空格
ss = re.sub("([^\\sA-Z\\-])([A-Z])", "\\1 \\2", ss)
# 删除重复空格
ss = ss.replace(" ", " ")
ss = ss.replace("。", ".")
# 删除,?!,前的多个空格
ss = re.sub(" *([\\.\\?\\!\\,])", "\\1", ss)
# 删除'的前后多个空格
ss = re.sub(" *([\\']) *", "\\1", ss)
# 删除换行后的多个空格, 通常时第二行的开始的多个空格
ss = re.sub('\n\\s*', '\n', ss)
# 删除开始的多个空格
ss = re.sub('^\\s*', '', ss)
# 删除-左侧空格
ss = re.sub("([A-Za-z0-9]) (\\-[A-Za-z0-9])", '\\1\\2', ss)
# 删除%左侧空格
ss = re.sub("([A-Za-z0-9]) %", '\\1%', ss)
# 结尾·改成.
ss = re.sub('·$', '.', ss)
# 移除Dr.后的空格
ss = re.sub(r'\bDr\. *\b', "Dr.", ss)
# 中文引号转英文
ss = re.sub(r'[""]', "\"", ss)
# 中文逗号转英文
ss = re.sub(r',', ",", ss)
# .,?后面加空格
ss = re.sub('([\\.,\\!\\?])([A-Za-z0-9\\u4e00-\\u9fa5])', '\\1 \\2', ss)
ss = ss.replace("\n\n", "\n")
sub.text = ss.strip()
if original_text != sub.text:
modified_count += 1
except Exception as e:
print(f"Error: Failed to process subtitle line {index+1}: {str(e)}")
print(traceback.format_exc())
# Keep original text unchanged
continue
try:
subs.save(path, encoding='utf-8')
print(f"Successfully processed subtitle file: {path}, modified {modified_count} lines")
return True
except Exception as e:
print(f"Error: Failed to save subtitle file: {str(e)}")
print(traceback.format_exc())
return False
except Exception as e:
print(f"Critical error occurred while executing reformat.py: {str(e)}")
print(traceback.format_exc())
return False
if __name__ == '__main__':
path = "/home/yao/Videos/null.srt"
execute(path)