阅读文本 / Reading text
本文使用合成样本演示处理方法。代码已通过隔离环境中的示例检查;这不代表对所有真实文件或产品效果的保证。处理重要文件前,请保留原件,并按文中的边界与验收项复核。
字幕文字翻译完了,时轴被挤进同一行,播放器就可能无法正确读取。SRT 的序号、时间范围、正文行与段落空行各有作用。检查时应保留这些层次,不用整份文件的换行总数判断质量。
先限定接受的 SRT 方言
下面只支持常见的序号加
HH:MM:SS,mmm --> HH:MM:SS,mmm
格式,每个块至少一行正文。它不处理样式扩展、字幕定位信息或其他字幕格式。合成协议还要求顺序连续且时段不重叠;真实项目允许重叠时应另行调整这一规则。
把格式解析与时间比较分开
import re
STAMP = r"[0-9]{2}:[0-9]{2}:[0-9]{2},[0-9]{3}"
def millis(text):
h, m, rest = text.split(":")
s, ms = rest.split(",")
if int(m) >= 60 or int(s) >= 60:
raise ValueError("invalid minute or second")
return ((int(h) * 60 + int(m)) * 60 + int(s)) * 1000 + int(ms)
def parse_srt(text):
blocks = re.split(r"\n[ \t]*\n", text.replace("\r\n", "\n").strip())
result, previous_end = [], 0
for index, block in enumerate(blocks, 1):
lines = block.splitlines()
if len(lines) < 3 or lines[0] != str(index):
raise ValueError("sequence or body missing")
match = re.fullmatch(f"({STAMP}) --> ({STAMP})", lines[1])
if not match:
raise ValueError("invalid timestamp line")
start, end = map(millis, match.groups())
if start < previous_end or end <= start:
raise ValueError("overlap or reversed interval")
result.append((start, end, lines[2:]))
previous_end = end
return result
sample = "1\n00:00:01,000 --> 00:00:02,000\nHello\nWorld\n\n2\n00:00:02,500 --
> 00:00:03,000\nNext"
parsed = parse_srt(sample)
assert parsed[0] == (1000, 2000, ["Hello", "World"])
assert len(parsed) == 2
try:
parse_srt(sample.replace("00:00:02,500", "00:00:01,500"))
except ValueError:
pass
else:
raise AssertionError("overlap accepted by strict example contract")
翻译前后比较受保护部分
项目
期望
不能替代的检查
序号与块数
按项目约定保留
是否确实漏译
时间范围
未授权时不改
对话与画面同步
正文行
可读且不混入时轴
阅读速度与语言自然度
空行分隔
保持块边界
播放器实际兼容性
结构通过之后还要播放
代码没有测量阅读速度,也不知道画面中的说话人。正式交付应使用目标播放器检查显示、换行和同步,尤其是字幕变长的语言。结构检查能提前拦住一部分错误,但不能把播放验收省掉。
把格式约束交给翻译工作流
借助
OmniDoc(产品入口)
评估相关文档翻译时,先确认当前入口是否支持所需字幕格式,并明确时轴需要保留。本文不据此宣称平台提供某个字幕接口;可复用的是“结构不变、正文可审”的验收思路。
参考:
Python 日期与时间类型
。本例用整数毫秒比较相对时轴,不把字幕时间当作某一天的墙上时间。
- 1 -
更新于 2026-10-08