SRT/ASS字幕无内置时间偏移字段,仅存绝对时间戳;解析需提取SRT的“HH:MM:SS,mmm”或ASS的“H:MM:SS.ss”时间字段,转为毫秒整数以便加减偏移,写回时须严格格式化:SRT毫秒补零至三位,ASS小数秒保留两位。

如何识别 SRT/ASS 字幕文件中的时间偏移字段
字幕文件本身不定义「时间偏移参数」——它只存绝对时间戳。所谓“偏移”,是播放时由外部控制的逻辑,不是文件内某个可解析的 offset 字段。SRT 中的 00:01:23,456 --> 00:01:25,789 是起止时刻;ASS 中的 Dialogue: 0,0:01:23.45,0:01:25.78,Default,,0,0,0,,{\an7}Hello 同样是绝对时间(单位为秒,含小数)。如果你看到带偏移的字幕,大概率是播放器或工具在加载时额外加了 Shift 操作,而非文件里写了偏移值。
所以解析目标其实是:提取每行的时间字段,并支持后续做加减运算来模拟偏移。
用 C++ 逐行解析 SRT 时间码(含毫秒)
SRT 时间格式固定为 HH:MM:SS,mmm,逗号分隔毫秒,且每段有 --> 分隔。直接用 std::getline + std::sscanf 最稳,避免正则依赖和异常开销。
- 跳过空行和序号行(纯数字行),定位到含
-->的行 - 对
"00:01:23,456 --> 00:01:25,789"调用sscanf(line.c_str(), "%d:%d:%d,%d --> %d:%d:%d,%d", &h1,&m1,&s1,&ms1, &h2,&m2,&s2,&ms2) - 转成毫秒整数:
total_ms = ((h * 3600 + m * 60 + s) * 1000 + ms),便于后续统一加减偏移量 - 注意:SRT 允许毫秒为三位或更少(如
,12),sscanf会截断,建议先用find定位逗号再手动取子串转整
ASS 文件中提取 Dialogue 行的时间字段(第 2、3 列)
ASS 的时间字段在 Dialogue: 行的第 2 和第 3 个逗号分隔字段,格式为 0:01:23.45(点号分隔小数秒)。不能直接 sscanf 因为字段位置不固定(前面可能有注释或空格),需按逗号切分。
- 用
std::string::find_first_of(",")找到第 1、2 个逗号位置,再用substr提取第 2 和第 3 段 - 对每段调用
sscanf(segment.c_str(), "%d:%d:%lf", &h, &m, &s),lf接收小数秒(如23.45→s=23.45) - 转毫秒:
static_cast,注意(round((h*3600+m*60+s)*1000)) round防止浮点误差(如0.001秒变成0) - 别忽略
Comment:行——它格式相同但不应参与时间计算,需先检查行首是否为"Dialogue:"
应用偏移时务必区分「写回文件」和「内存修正」
真正容易出错的地方不在解析,而在偏移后的写入逻辑。SRT 要求毫秒必须补足三位(00:01:23,005 不可写成 00:01:23,5),ASS 要求小数秒最多两位(0:01:23.45,不是 .450 或 .4)。
- SRT 输出:用
printf("%02d:%02d:%02d,%03d", h,m,s,ms%1000),ms%1000防止进位溢出(如 1005ms → 1s5ms) - ASS 输出:把毫秒转回秒级浮点后,用
std::fixed 控制小数位,再手动删尾随零(23.40→23.4) - 别在解析阶段就修改原始字符串——保留原始格式信息,偏移只作用于数值,输出时再格式化,否则多次处理会累积精度丢失
时间码的进位边界(如 59分59秒999毫秒+1ms)必须显式处理,C++ 没有内置时间类型帮你兜底。解析完做偏移前,先转成单一毫秒整数,做完加减再拆解,是最不容易翻车的方式。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











