srt文件按空行分隔条目,每条含纯数字序号、含“ --> ”的时间轴行(格式如00:01:23,456 --> 00:01:25,789)及可跨行的正文;ass更复杂,需跳过注释、定位[events]节,解析dialogue:行并从右往左找第9个逗号以提取字幕文本,时间戳应手动分割计算总毫秒数,推荐流式逐行解析而非全文加载。

怎么读SRT文件的序号、时间轴和正文
SRT格式本质是纯文本,靠空行分隔条目,每条由序号、时间轴、多行字幕文本组成。直接用std::ifstream逐行读取最稳妥,别用getline一次性读整个块——容易因换行不一致(Windows/Linux)或空格缩进错位而解析失败。
关键点:序号行必须是纯数字;时间轴行必须含-->且前后有空格;字幕正文可跨行,但下一条的序号行或文件结尾是它的终止信号。
- 用
std::string::find(" --> ")定位时间轴行,比正则快且无依赖 - 时间格式如
00:01:23,456 --> 00:01:25,789,毫秒用逗号分隔,不是英文句点 - 遇到空行就结束当前条目,立即开始下一条;文件末尾没空行也要手动触发保存最后一条
ASS文件解析难点在格式头和样式控制码
ASS比SRT复杂得多:开头有[Script Info]、[V4+ Styles]、[Events]三个强制节区,且字幕正文里混着{\i1}斜体{\i0}这类控制码。硬切字符串会崩,必须按节跳转。
先跳过所有以;开头的注释行;遇到[Events]后才开始解析字幕事件;每一行Dialogue:开头的才是有效字幕,字段用英文逗号分隔,共10个固定位置(第10字段才是字幕文本)。
-
Dialogue:行中,第1–9字段不能直接split(","),因为第10字段本身可能含未转义的逗号(比如Dialogue: 0,0:00:01.00,0:00:03.00,Default,,0,0,0,,Hello, world!) - 正确做法:从右往左找第9个逗号(即第10字段起始位置),用
substr截取 - 控制码如
{\an8}、{\c&HFF0000&}可暂忽略,除非你要渲染——保留原样存入text字段即可
时间戳转换:别用sscanf硬解HH:MM:SS,mmm
手写sscanf(line.c_str(), "%d:%d:%d,%d", &h, &m, &s, &ms)看似简单,但ASS里时间可能只有0:01:23.45(缺前导零)或00:01:23.4567(毫秒超三位),sscanf会截断或匹配失败。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
更稳的方式是用std::string::find_first_of(":,." )定位分隔符,逐段std::stoi,再加权计算总毫秒数:
int h = std::stoi(time_str.substr(0, colon1)); int m = std::stoi(time_str.substr(colon1+1, colon2-colon1-1)); int s = std::stoi(time_str.substr(colon2+1, comma-colon2-1)); int ms = std::stoi(time_str.substr(comma+1)); // 自动截断多余位数 int total_ms = ((h * 60 + m) * 60 + s) * 1000 + ms;
- ASS里时间也可能用英文句点
.作毫秒分隔符,需统一替换为逗号再处理 - 某些老旧SRT用句点,得兼容;但标准SRT规范要求用逗号,优先按逗号解析,失败再 fallback 到句点
内存布局:别把整文件读进std::string再切
大型字幕文件(尤其ASS带大量样式定义)可能几MB,std::string一次性加载再find/substr会产生多次拷贝,CPU缓存不友好。流式解析更轻量。
用std::ifstream配合std::getline逐行读,每行只存当前上下文需要的数据(比如只记当前节区名、上一行是否为空、当前是否在[Events]内),状态机驱动比正则或全文匹配更可控。
- 定义一个结构体
SubtitleEntry,只存start_ms、end_ms、text三个字段,避免冗余字段拖慢vector扩容 - ASS的
[V4+ Styles]节可以跳过,除非你要做字体/颜色渲染;但至少要读完[Events]前的所有节,否则可能漏掉PlayResX等影响布局的参数 - Windows下文件编码可能是GBK或UTF-16,
std::ifstream默认按本地编码读——若遇到乱码,需用std::wifstream+std::codecvt_utf8<wchar_t></wchar_t>,但代价高;实际项目中建议外部统一转UTF-8再喂给解析器
真正麻烦的不是语法,是不同编辑器导出的SRT/ASS五花八门:有的空行多,有的时间轴前后空格数不一,有的ASS把Dialogue:写成Comment:。解析器得容忍这些“合法但难看”的变体,而不是指望输入永远标准。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










