SubRip时间轴格式为“HH:MM:SS,mmm --> HH:MM:SS,mmm”,因含冒号、逗号且非标准ISO/RFC格式,不能直接用std::stoi解析;需先切分、归一化分隔符、补零截断毫秒,再分段转整数并按公式换算总毫秒数。

SubRip时间轴格式长什么样,为什么不能直接用std::stoi拆
SubRip(.srt)的时间轴标记形如 00:01:23,456 --> 00:01:25,789,注意逗号分隔毫秒、冒号分隔时分秒——这不是ISO 8601,也不是RFC 3339,更不是std::chrono原生支持的格式。直接对整个字符串调用std::stoi会停在第一个冒号就报错,而用sscanf又容易忽略千位分隔符(比如某些编辑器导出用点号.代替逗号),导致毫秒解析成456000或456。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 先按空格切分,取第1个和第3个字段(即起始和结束时间字符串)
- 对每个时间字符串,统一把
,或.替换成:,再按:切为4段(时:分:秒:毫秒) - 确保毫秒字段恒为3位:不足补0,超3位截断(常见错误是把
1234当1234ms,实际应为234ms) - 用
std::stoi逐段转整数,再套公式:total_ms = h*3600000 + m*60000 + s*1000 + ms
用std::regex匹配时间轴的安全边界在哪
正则能写得简洁,但C++11的std::regex在GCC低版本(如4.8)有性能缺陷,且不支持原子组,遇到畸形输入(比如00:01:23,45,678)可能回溯爆炸。生产环境不建议用std::regex做关键路径解析。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 仅在调试或小文件场景用,模式推荐:
R"((\d{2}):(\d{2}):(\d{2})[,.](\d{3}))" - 必须检查
std::regex_match返回true,且smatch.size() == 5(含全匹配项) - 匹配后仍要验证各组数值范围:小时≤23,分钟≤59,秒≤59,毫秒≤999
- 若需跨平台稳定,改用手工
find_first_of+substr切片,速度更快、无依赖
std::getline读.srt时怎么跳过空行和序号行
.srt标准结构是「序号→时间轴→字幕文本→空行」,但实际文件常有额外空行、BOM头、Windows/Linux换行混用。用std::getline逐行读时,如果只判断line.empty(),会把带空格的“伪空行”(如" ")漏掉,导致序号解析错位。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 定义辅助函数
trim(const std::string& s),用find_first_not_of和find_last_not_of去首尾空白 - 读到一行后,先
trim,再判断:if (line.empty()) continue;;否则尝试std::stoi(line)看是否为纯数字(注意捕获std::invalid_argument) - 序号行之后必然是时间轴行,所以检测到有效序号后,下一行必须匹配时间轴格式,否则视为损坏,丢弃当前块
- 字幕正文可能有多行,要持续
getline直到再次遇到空行或EOF
毫秒精度丢失的典型表现和修复点
最隐蔽的问题是:把00:00:01,000和00:00:01.000当成相同值,但某些播放器(如VLC旧版)对分隔符敏感;更严重的是,用float或double存总毫秒数,会导致大时间戳(如2小时后)的整数部分精度丢失(double对>2^53的整数无法精确表示)。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 全程用
int64_t存毫秒数,避免浮点运算 - 解析毫秒字段时,严格按字符长度处理:取前3位,
substr(0,3),再stoi,不要用stof * 1000 - 输出时反向转换:用
ms % 1000得毫秒,(ms / 1000) % 60得秒,依此类推,确保格式化后恒为HH:MM:SS,mmm - 测试用例必须覆盖边界:23:59:59,999 → 00:00:00,000(跨天)、00:00:00,000 → 00:00:00,001(最小增量)
真正难的不是拆字符串,而是处理现实世界里那些没按规范写的.srt——手动生成的、AI批量导出的、不同编辑器混用的。时间轴一旦偏移,字幕就永远追不上画面,这种问题在线上环境几乎无法热修复。



















