ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Lingarr字幕解析器源码解读:SRT与SSA解析/写入的完整实现原理

Lingarr字幕解析器源码解读:SRT与SSA解析/写入的完整实现原理

Lingarr字幕解析器源码解读:SRT与SSA解析/写入的完整实现原理

【免费下载链接】lingarrLingarr is an application that supports both local and SaaS translation services to translate subtitle files into a specified target language. With automated translation options, Lingarr simplifies translating subtitles.项目地址: https://gitcode.com/gh_mirrors/li/lingarr

Lingarr 是一款支持本地与 SaaS 翻译服务的字幕翻译工具,而它最核心的地基,就是内置在Lingarr.Server/Services/Subtitle/目录下的字幕解析器与写入器。无论是 SRT 还是 SSA/ASS 格式,Lingarr 都要先把字幕文件解析成统一的SubtitleItem对象,翻译完成后再按原格式写回。本文带你逐层拆解 Lingarr 字幕解析器的完整实现原理,看看它是如何在毫秒级时间轴上完成"读取→清洗→翻译→写回"的全流程。

Lingarr字幕解析器整体架构:一条流水线打通两种格式

Lingarr 没有为每种格式写死逻辑,而是定义了统一接口,让上层代码完全不用关心文件格式:

  • ISubtitleParser:负责把字幕流解析成List<SubtitleItem>,接口定义见 ISubtitleParser.cs;
  • ISubtitleWriter:负责把翻译后的字幕对象异步写回流,接口定义见 ISubtitleWriter.cs;
  • SubtitleItem:统一的数据载体,包含序号Position、毫秒级起止时间StartTime/EndTime、原始行Lines、纯文本行PlaintextLines和翻译行TranslatedLines,定义见 SubtitleItem.cs。

调度层在 SubtitleService.cs 中通过扩展名路由:.srt交给SrtParser/SrtWriter.ssa/.ass交给SsaParser/SsaWriter。这意味着翻译引擎拿到的永远是同一种对象,格式差异被完全隔离在解析器内部。👍

SRT字幕解析原理详解:逐块读取与时间轴容错

SRT(SubRip)格式结构简单:序号行、时间码行、若干文本行、空行分隔。SrtParser的解析策略非常稳健:

1. 按"块"累积,用序号识别边界

解析器逐行读取非空内容,当读到一行纯数字、且当前块的首行也是数字时,就判定这是一条新字幕的开始,于是把上一块送进TryParseBlock处理。这种"数字对数字"的判断方式比依赖空行更宽容,能应对空行缺失的畸形文件。

2. 时间码解析:兼容逗号与小数点

SRT 时间码形如00:00:01,000 --> 00:00:04,500,而SrtParser用正则TimeCodeRegex解析,并做了两个贴心处理:

  • 毫秒分隔符兼容:正则里[,\.]同时接受逗号和点号,某些工具导出的00:00:01.000也能正常解析;
  • 毫秒位数补齐01会被PadRight(3,'0')补成010毫秒,不会出现 1 毫秒被当成 10 毫秒的错误;
  • 防呆校验:分钟和秒超过 59 直接判为非法,如果结束时间早于开始时间还会自动交换,避免脏数据污染后续翻译。

3. 文本清洗与纯文本双通道

每条字幕同时保留原始行(含{\an8}<i>等标记)和清洗后的纯文本行(供翻译引擎使用),这样翻译完成后还能尽量还原原始样式。核心清洗逻辑RemoveMarkup的源码在 SubtitleFormatterService.cs,稍后单独展开。

SRT字幕写入原理:毫秒转时间码的格式化艺术

SrtWriter的写入逻辑集中在 SrtWriter.cs,核心技巧有两点:

  • TimeSpan 格式化:把毫秒整数转成TimeSpan后,用{start:hh\:mm\:ss\,fff}输出标准 SRT 时间码,逗号需要转义,确保输出永远是00:00:01,000 --> 00:00:04,500的规范形态;
  • 序号复用原位置:写入时直接使用subtitleItem.Position作为条目序号,保证经过"解析→翻译→写回"后字幕编号不乱。

写入采用异步WriteLineAsync流式输出,条目之间补一个空行,符合 SRT 规范,播放器都能正确识别。😊

SSA/ASS字幕解析原理详解:分区状态机与列映射

SSA/ASS 比 SRT 复杂得多,文件由[Script Info][V4+ Styles][Events]分区组成,且 Dialogue 行是逗号分隔的表格结构。SsaParser用"状态机 + 列索引"两招化解:

1. 分区状态机

解析器维护currentSection变量,读到[开头的行就切换当前分区。不同分区走不同分支:[Script Info]收集元信息并解析WrapStyle换行模式;[V4+ Styles]原样收集样式;[Events]则是重头戏。

2. Format 列映射,Text 字段"只取不拆"

[Events]下的Format:行定义了列顺序(Marked, Start, End, Style, Name, MarginL/R/V, Effect, Text),解析器把它建成"列名→索引"字典。关键难点是Text 字段本身可能包含逗号(如{\pos(100,200)}),所以ParseDialogueLine用了FindTextFieldStart逐字符数逗号来定位 Text 起始位置,绝不整体Split(','),这部分实现见 SsaParser.cs。

3. 兼容老版 Aegisub 的缺列容错

有些老工具导出的 ASS 会省略 Layer 列,解析器会尝试"少一列"再定位 Text,若成功则自动补一个默认 Layer 值"0",保证下游列索引不错位,非常贴心。👏

4. WrapStyle 换行规则

ASS 的换行符有\N\n两种,含义取决于WrapStyle(枚举见 SsaWrapStyle.cs):Smart/EndOfLine模式只认\NNone模式则两种都视为换行。解析器会按此规则把整行文本拆成多行字幕文本。

SSA/ASS字幕写入原理:样式保留与格式剥离双模式

SsaWriter的写入策略体现了对粉丝字幕组的尊重:

  • 完整保留模式:原样写回[Script Info][V4+ Styles]和每条 Dialogue 的 Marked/Style/Margin/Effect 等字段,翻译后的文本用\N重新拼接(见 SsaWriter.cs);
  • 格式剥离模式:当用户勾选"去掉字幕格式"时,会生成精简的[V4+ Styles],优先复用源文件的Style: Default(保留下载站的字号字号设定),找不到时则按PlayResY动态计算字体大小(约为画布高度的 1/15,288 高度≈19px,1080 高度≈72px),并强制所有 Dialogue 使用 Default 样式、清空 Effect,输出干净统一的效果。

字幕标记清洗原理:RemoveMarkup 的层层过滤

翻译前必须把样式标记从文本中剥离,RemoveMarkup的过滤顺序很有讲究(源码见 SubtitleFormatterService.cs):

  1. 先剔除 ASS 绘图块{\p1}...{\p0}(这类矢量绘图数据一旦混入翻译会直接污染结果);
  2. 再删{...}样式标签(如{\an8}{\pos(...)});
  3. 接着删<...>HTML 风格标签(如<i><font>);
  4. \N\n\h\t等转义符统一替换成空格;
  5. 合并多余空格后,最后用矢量前缀正则^[mlcbsn]...识别以绘图命令开头(如m 0 0 l 100 100)的行,直接置空丢弃。

这套"先绘图、后标签、再转义、末过滤"的顺序,保证了送给翻译引擎的永远是干净可读的纯文本。✨

容错机制总结:为什么 Lingarr 能"扛住"脏字幕

综合四个解析/写入类的实现,Lingarr 字幕解析器的健壮性来自层层防御:

  • 流不可读或不可定位时直接拒绝(ValidateStream);
  • 解析失败不抛异常中断,而是记录日志返回空列表,让上层业务继续;
  • SRT 起止时间倒挂自动交换、SSA 缺 Layer 列自动补零;
  • 空文件、无有效字幕时给出明确的FormatException提示;
  • 解析后PlaintextLinesLines双轨保存,翻译失败也能回退原始文本。

结语

从 SRT 的逐块解析到 SSA 的列映射状态机,Lingarr 用清晰的接口分层和缜密的容错细节,把两种风格迥异的字幕格式统一成了同一条翻译流水线。无论你是想为 Lingarr 贡献新的字幕格式支持,还是想在自己的工具里实现类似能力,这份源码都是极佳的参考范本。相关代码集中位于Lingarr.Server/Services/Subtitle/Lingarr.Server/Models/FileSystem/,配合 SsaParserTests.cs 等测试用例,可以快速验证你对解析逻辑的理解。🚀

【免费下载链接】lingarrLingarr is an application that supports both local and SaaS translation services to translate subtitle files into a specified target language. With automated translation options, Lingarr simplifies translating subtitles.项目地址: https://gitcode.com/gh_mirrors/li/lingarr

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

返回列表