srt文件应按块切分而非逐行读:缓存非空行至遇空行即得一完整字幕块;时间码用find_first_of定位分隔符后分段转换,异常则标记无效;序号不可靠,应存入vector并按时间排序;utf-8字幕解析无需解码,输出乱码需设控制台编码为cp_utf8。

怎么读取SRT文件的结构而不被序号和空行搞乱
SRT 文件本质是纯文本,但格式松散:序号、时间码、多行字幕、空行交替出现。直接用 std::getline 逐行读容易在空行处断错,或把第二行时间当成字幕内容。关键不是“解析”,而是“按块切分”——每个字幕块以非空行开头,以连续空行结束。
实操建议:
- 用
std::string缓存当前块,每次读一行,遇到空行且缓存非空时,就完成一个块的提取 - 跳过首尾空白(
std::isspace),避免因 Windows/Linux 换行符差异误判空行 - 序号行必须是纯数字(可选带空格),别用
std::stoi直接转——万一有乱码会抛异常,先用std::all_of校验字符
时间码字符串怎么安全转成毫秒整数
SRT 时间码形如 00:01:23,456,逗号分隔毫秒,但有些老工具(包括某些 Subtitle Edit 版本)可能输出句点 . 或漏前导零。硬写 sscanf 容易崩,比如 0:5:7,89 这种不规范格式。
实操建议:
- 用
std::string::find_first_of(",:.")定位分隔符位置,分三段切:冒号前是小时,两个冒号间是分钟,第二个冒号到分隔符间是秒,分隔符后是毫秒 - 每段用
std::stoi转,捕获std::invalid_argument和std::out_of_range异常,出错则该条字幕标记为无效,不中止整个解析 - 毫秒字段不足3位(如
12)要补零再转,避免当成12毫秒而非120毫秒
为什么用 std::vector<subtitleentry></subtitleentry> 而不用 std::map<int ...></int>
有人想用序号当 key 存进 std::map,但 Subtitle Edit 导出的 SRT 序号未必连续(比如删过某条后重新编号,中间留空),甚至可能重复(手动编辑导致)。更麻烦的是,播放器实际依赖时间轴,不是序号。
实操建议:
- 定义结构体
SubtitleEntry,至少含start_ms、end_ms、text(std::string)三个字段 - 全部存进
std::vector,后续按需排序(用std::sort+ lambda 比较start_ms) - 如果要做二分查找(比如根据播放时间找当前字幕),排序后用
std::lower_bound,别自己写循环
处理中文等 UTF-8 字幕时,Windows 控制台直接 std::cout 是乱码
Subtitle Edit 默认保存为 UTF-8(无 BOM),但 VS 的控制台默认是 GBK,std::cout 会把 UTF-8 字节流当 GBK 解码,显示为乱码。这不是解析错了,是输出层问题。
实操建议:
- 解析阶段完全不用管编码——UTF-8 是字节序列,
std::string照存即可 - 若需调试输出,在 Windows 上用
SetConsoleOutputCP(CP_UTF8)(需<windows.h></windows.h>),并在程序开头调用一次 - 更稳妥的做法:调试时把
text写入 UTF-8 文件(用std::ofstream+.open(..., std::ios::binary)),用记事本或 VS Code 查看
真正难的不是读出字段,而是接受 SRT 本身没有标准——Subtitle Edit 可能导出带 HTML 标签的 <i>斜体</i>,也可能把换行写成 \n 或 <br>。解析器得明确目标:只取纯文本?还是保留简单格式?前者删标签就行,后者就得加个微型 HTML 解析器。这个边界不划清,后面永远在修 case。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











