字幕格式化
SRT / VTT / ASS / SSA / LRC 互转 · 字幕编辑 · 纯本地处理
SRT/VTT/ASS/LRC 互转
SRT / VTT / ASS / SSA / LRC 互转 · 字幕编辑 · 纯本地处理
SRT(SubRip):最通用格式,HH:MM:SS,mmm 时间码 + 序号 + 文本,几乎所有播放器支持。
VTT(WebVTT):HTML5 视频原生字幕格式,HH:MM:SS.mmm,开头有 WEBVTT 头。
ASS / SSA(Advanced SubStation Alpha):支持复杂样式(颜色 / 位置 / 动画)的高级格式。
LRC:歌词格式,[mm:ss.xx] 行标记,多用于卡拉 OK。
了解工具定位 · 使用场景 · 对比优势
将 SRT、VTT、ASS、LRC 字幕格式互相转换,无需安装软件。视频剪辑师、字幕组、外语学习者在处理不同平台的字幕文件时,直接上传即可批量完成格式统一。转换过程在浏览器本地执行,原始文件不会上传到服务器。
视频创作者从不同渠道获取字幕文件,有的来自 YouTube 自动生成(SRT),有的来自字幕组(ASS),有的来自听写软件(VTT)。剪辑时导入软件只支持单一格式,逐个手动转换费时且易出错。本工具一键将多种来源字幕统一为剪辑软件所需的格式,保留时间轴精度和样式信息,让多轨字幕素材无缝对接时间线。
播客制作人需要为音频节目配上同步显示的文本内容(类似歌词),但录音软件只导出 LRC 格式,而播客平台要求 SRT 或 VTT。手动逐句调整时间戳和格式非常繁琐。本工具将 LRC 快速转为 SRT/VTT,自动校准时间轴偏移,同时支持批量处理多期节目,大幅缩短后期制作时间。
语言学习者下载了带 ASS 字幕的双语电影,想提取纯中文或纯外文字幕导入笔记软件做精听。ASS 文件内嵌样式和特效,直接复制会带乱码。本工具将 ASS 转为纯文本 SRT,去除样式干扰,保留时间轴以便定位原句;还可选择只保留指定语言轨道,生成干净的学习素材。
企业会议录制后,语音转写工具输出 VTT 格式字幕,但内部知识库系统只接受 SRT 格式。每次手动改文件头、调整时间戳分隔符,重复劳动且容易出错。本工具在线转换,无需安装软件,上传 VTT 秒出 SRT,保留所有时间节点和文本内容,确保会议记录格式统一归档。
| 维度 | 本工具 | 竞品 A (Subtitle Edit) | 传统方法 |
|---|---|---|---|
| 数据隐私 | 纯浏览器处理,文件不上传服务器 | 本地桌面软件,文件不离开电脑 | 文件需发送给第三方或人工处理 |
| 处理速度 | 1 秒内完成转换 | 秒级完成,取决于文件大小 | 手动逐条复制粘贴,数分钟至数小时 |
| 离线可用 | 完全离线,无需网络 | 完全离线 | 完全离线 |
| 平台兼容 | 任何现代浏览器 (Win/Mac/Linux) | 仅 Windows (有 Linux 实验版) | 任何平台,但需手动操作 |
| 格式支持 | SRT/VTT/ASS/LRC 互转 | 支持 100+ 字幕格式,功能更全面 | 仅支持用户熟悉的手动格式 |
| 使用门槛 | 打开网页,拖拽文件即用 | 需下载安装,学习界面操作 | 需掌握字幕格式语法,易出错 |
| 批量处理 | 单次单个文件 | 支持批量转换和编辑 | 不支持,需逐个文件手动处理 |
| 附加功能 | 纯格式转换,无编辑功能 | 内置时间轴调整、OCR、翻译等 | 无,纯手动操作 |
上手步骤 · 输入输出 · 避坑提示
| 输入 | 输出 | 说明 |
|---|---|---|
| 1 00:00:01,000 --> 00:00:04,000 Hello, world! | WEBVTT 1 00:00:01.000 --> 00:00:04.000 Hello, world! | 典型场景:SRT 转 VTT,时间码格式变化 |
| WEBVTT 1 00:00:01.000 --> 00:00:04.000 Hello, world! | 1 00:00:01,000 --> 00:00:04,000 Hello, world! | 典型场景:VTT 转 SRT,时间码格式还原 |
| [00:00.50]Hello [00:02.00]world | 1 00:00:00,500 --> 00:00:02,000 Hello 2 00:00:02,000 --> 00:00:04,000 world | 边界 case:LRC 转 SRT,需推断结束时间 |
| 1 00:00:01,000 --> 00:00:04,000 Hello, world! 2 00:00:05,000 --> 00:00:08,000 This is a test. | WEBVTT 1 00:00:01.000 --> 00:00:04.000 Hello, world! 2 00:00:05.000 --> 00:00:08.000 This is a test. | 典型场景:多行字幕批量转换 |
| Dialogue: 0,0:00:01.00,0:00:04.00,Default,,0,0,0,,Hello, world! | 1 00:00:01,000 --> 00:00:04,000 Hello, world! | 边界 case:ASS 格式,需解析样式字段 |
| 1 00:00:01,000 --> 00:00:04,000 Hello, world! 2 00:00:05,000 --> 00:00:08,000 Line 2 | 1 00:00:01,000 --> 00:00:04,000 Hello, world! 2 00:00:05,000 --> 00:00:08,000 Line 2 | 易错 case:输入含多余空行,工具自动清理 |
| 1 00:00:01,000 --> 00:00:04,000 Hello, world! 2 00:00:05,000 --> 00:00:08,000 Line with <b>bold</b> text | 1 00:00:01,000 --> 00:00:04,000 Hello, world! 2 00:00:05,000 --> 00:00:08,000 Line with <b>bold</b> text | 易错 case:HTML 标签在 SRT 中保留,VTT 需确认 |
00:00:01.500 --> 00:00:04.00000:00:01,500 --> 00:00:04,000SRT 标准使用英文逗号作为毫秒分隔符(不是点),点号会导致解析器无法识别时间轴,整段字幕被跳过。
Style: Default,Arial,16,&HFFFFFF,&H000000,&H000000,&H000000,0,0,0,0,100,100,0,0,1,1,0,2,10,10,10,1Style: Default,Arial,16,&H00FFFFFF,&H000000FF,&H00000000,&H00000000,0,0,0,0,100,100,0,0,1,1,0,2,10,10,10,1ASS 颜色格式为 &HAABBGGRR(Alpha + 蓝绿红),且必须为 8 位十六进制;缺少 Alpha 位或顺序错误会导致颜色显示异常。
00:00:01.500 --> 00:00:04.000
Hello worldWEBVTT
00:00:01.500 --> 00:00:04.000
Hello worldWebVTT 规范要求文件第一行必须是 'WEBVTT'(可含 BOM),否则浏览器 `<track>` 元素拒绝加载,播放器不显示字幕。
[00:01.50]Hello world[00:01.50] Hello worldLRC 格式要求时间标签后跟一个空格再写歌词;无空格时部分解析器会将 ']H' 视为同一 token 导致歌词被吞掉。
Dialogue: 0,0:00:01.00,0:00:04.00,Default,,0,0,0,,{这行文字包含花括号}Dialogue: 0,0:00:01.00,0:00:04.00,Default,,0,0,0,,\{这行文字包含花括号\}ASS 使用大括号 `{}` 作为样式覆盖标签的定界符;未转义的普通大括号会被解释为样式指令,导致文字不显示或样式错乱。
1
00:00:01,500 --> 00:00:04,000
Hello world
2
00:00:05,000 --> 00:00:08,000
World1
00:00:01,500 --> 00:00:04,000
Hello world
2
00:00:05,000 --> 00:00:08,000
WorldSRT 标准要求每条字幕块之间用空行分隔;缺少空行会导致解析器将下一条序号视为上一条的文本内容,造成字幕合并或丢失。
00:00:01,500 --> 00:00:04,00000:00:01.500 --> 00:00:04.000WebVTT 标准规定毫秒分隔符为英文点号 `.`,与 SRT 的逗号相反;使用逗号会导致时间解析失败,字幕不显示。
[00:1:50]Hello[00:01.50]HelloLRC 标准时间格式为 `[mm:ss.xx]`,分钟和秒均为两位数;省略前导零或使用冒号分隔毫秒会导致解析器无法正确匹配时间轴。
公式推导 · 流程图解 · 依据出处
SRT → VTT: 将时间轴格式从 `HH:MM:SS,mmm` 转换为 `HH:MM:SS.mmm`,并添加 `WEBVTT` 头部;VTT → SRT: 反向转换。ASS → SRT: 移除所有样式标签(如 \fn, \fs, \c 等),仅保留纯文本。LRC → SRT: 将 `[mm:ss.xx]` 时间戳转换为 `HH:MM:SS,mmm`,并合并同一时间点的多行歌词为单条字幕。
HH:MM:SS,mmm — SRT 时间格式,逗号分隔毫秒HH:MM:SS.mmm — VTT 时间格式,点分隔毫秒样式标签 — ASS 中的字体/颜色/位置等控制码[mm:ss.xx] — LRC 时间戳,分:秒.百分秒将 SRT 文件 `1\n00:01:15,500 --> 00:01:18,200\nHello world` 转为 VTT:添加 `WEBVTT` 头部,时间轴改为 `00:01:15.500 --> 00:01:18.200`,内容不变。再将此 VTT 转为 ASS:需手动添加样式定义(如 `Style: Default,Arial,20,&H00FFFFFF,...`),时间轴格式不变。最后转为 LRC:时间轴改为 `[01:15.50]Hello world`,并移除所有样式信息。
适用于标准 SRT/VTT/ASS/LRC 格式的字幕文件互转。不兼容非标准变体(如 SRT 缺少序号、VTT 缺少 WEBVTT 头部、ASS 使用自定义扩展标签)。转换基于格式规范(SRT 遵循 RFC 草案,VTT 遵循 W3C 标准,ASS 遵循 Aegisub 规范,LRC 遵循通用歌词格式)。
3 种主流语言 · 复制即用
import re
# SRT → VTT 格式转换
srt_text = """1
00:00:01,000 --> 00:00:04,000
Hello, world!
2
00:00:05,000 --> 00:00:08,000
This is a subtitle."""
def srt_to_vtt(srt):
# 替换逗号为点(VTT 时间格式)
vtt = srt.replace(',', '.')
# 添加 VTT 文件头
return 'WEBVTT\n\n' + vtt
vtt_text = srt_to_vtt(srt_text)
print(vtt_text)
# 输出:
# WEBVTT
#
# 1
# 00:00:01.000 --> 00:00:04.000
# Hello, world!
#
# 2
# 00:00:05.000 --> 00:00:08.000
# This is a subtitle.package main
import (
"fmt"
"strings"
)
// VTT → SRT 格式转换
func vttToSrt(vtt string) string {
// 移除 WEBVTT 头部
srt := strings.Replace(vtt, "WEBVTT\n\n", "", 1)
// 替换点为逗号(SRT 时间格式)
srt = strings.ReplaceAll(srt, ".", ",")
return srt
}
func main() {
vttText := `WEBVTT
1
00:00:01.000 --> 00:00:04.000
Hello, world!
2
00:00:05.000 --> 00:00:08.000
This is a subtitle.`
srtText := vttToSrt(vttText)
fmt.Println(srtText)
// 输出:
// 1
// 00:00:01,000 --> 00:00:04,000
// Hello, world!
//
// 2
// 00:00:05,000 --> 00:00:08,000
// This is a subtitle.
}// LRC → SRT 格式转换
const lrcText = `[00:01.00]Hello, world!
[00:05.00]This is a subtitle.`
function lrcToSrt(lrc) {
const lines = lrc.split('\n')
let srtLines = []
let index = 1
for (const line of lines) {
const match = line.match(/\[(\d{2}):(\d{2})\.(\d{2})\]\s*(.*)/)
if (!match) continue
const [, min, sec, ms, text] = match
// 将 LRC 时间格式转为 SRT 格式(假设每句持续 3 秒)
const start = `${min}:${sec}:${ms},000`
const endMin = String(Number(min) + (Number(sec) + 3 >= 60 ? 1 : 0)).padStart(2, '0')
const endSec = String((Number(sec) + 3) % 60).padStart(2, '0')
const end = `${endMin}:${endSec}:${ms},000`
srtLines.push(`${index}\n${start} --> ${end}\n${text}`)
index++
}
return srtLines.join('\n\n')
}
console.log(lrcToSrt(lrcText))
// 输出:
// 1
// 00:01:00,000 --> 00:01:03,000
// Hello, world!
//
// 2
// 00:05:00,000 --> 00:05:03,000
// This is a subtitle.8 个高频疑问