解析 SRT 字幕时,时间戳格式不匹配就直接崩
常见错误是用
DateTime.Parse直接转
"00:01:23,456",但 SRT 的毫秒分隔符是逗号,而 .NET 默认认点号;更糟的是有些文件用分号(老版规范),或缺前导零。一解析就抛
FormatException。
正确做法是手写解析逻辑,别依赖通用时间解析:
用string.Split拆开
"-->"两边,再对每段按
":"和
","或
";"分割 小时、分钟、秒转
int,毫秒部分用
int.TryParse(..., out var ms)防逗号/分号混用 构造
TimeSpan:
new TimeSpan(0, hours, minutes, seconds, ms),别碰
DateTime
示例片段:
var parts = line.Split(new[] { " --> " }, StringSplitOptions.None);
var startParts = Regex.Split(parts[0].Trim(), @"[:;,]");
// 然后逐段 int.TryParse
VTT 解析要小心头部的 WEBVTT 声明和注释行
很多人直接
File.ReadAllLines后从第 0 行开始 parse,结果把
WEBVTT、空行、
NOTE行当成了字幕块,导致索引错乱、ID 错位。
VTT 是有明确起始标识的文本格式,必须跳过非字幕内容:
逐行读,遇到第一个符合^\d+$的行才开始当作序号(可选),下一行才是时间轴 时间轴行必须含
-->且前后都有有效时间格式,否则跳过 字幕正文以空行结束;遇到新序号或 EOF 才收尾当前条目 别假设每条都带序号——VTT 允许省略,SRT 则强制有
生成 SRT/VTT 时,换行和编码不处理好,播放器直接拒载
Windows 记事本打开正常,PotPlayer/VLC 却显示乱码或只读第一行?大概率是用了
\n换行 + UTF-8 无 BOM。SRT/VTT 规范要求 CRLF(
\r\n),且多数播放器(尤其旧版)只认 UTF-8 with BOM。
写文件时两个关键点不能漏:
用Encoding.UTF8.GetBytes+
File.WriteAllBytes,或指定
new StreamWriter(path, false, new UTF8Encoding(true))(
true表示带 BOM) 每行结尾必须是
"\r\n",别用
Environment.NewLine——它在 Linux/macOS 是
\n,会坏掉 SRT 序号后必须跟
\r\n,时间行后也必须跟
\r\n,字幕正文末尾不能多一个空行
时间精度差异会让字幕快进或延迟几帧
SRT 只支持毫秒(三位),VTT 支持毫秒甚至微秒(但实际只取三位)。如果你从视频帧时间(比如 23.976 fps 下的
TimeSpan.FromTicks)直接 ToString() 写入,可能生成
00:01:23.456789这种非法格式,部分播放器截断、部分报错。
统一做截断处理:
提取总毫秒数:(int)timeSpan.TotalMilliseconds % 1000避免四舍五入——字幕对齐靠的是向下取整,否则 999.8ms 会进到下一秒,造成跳断 VTT 中时间推荐用
hh:mm:ss.fff格式输出,SRT 同理,但分隔符用
,
真正麻烦的是跨格式转换:SRT 转 VTT 时,别把
,456直接换成
.456就完事,得确认原始时间源有没有被 double 转换污染过——浮点误差叠一次就偏 1~2ms,连播 10 分钟可能偏半秒。
