Python代码实现将USF字幕格式转换为SRT
字幕处理:USF 字幕格式转换为 SRT
在影音处理、字幕整理、视频本地化等场景中,我们经常会遇到不同字幕格式需要互转的情况,其中 USF(Universal Subtitle Format) 是一种基于 XML 的字幕格式,而 SRT(SubRip Subtitle)则是最常见、最被播放器和编辑软件支持的格式。
本文分享一段 实战 Python 代码,完成 USF → SRT 转换,并对处理流程、注意事项、关键逻辑逐行解析,开箱即用。
USF 与 SRT 有什么区别
| 特性 | USF | SRT |
|---|---|---|
| 结构 | 基于 XML | 文本文件 |
| 时间格式 | HH:MM:SS.sss | HH:MM:SS,mmm |
| 支持样式 | 字体、大小、颜色等丰富信息 | 纯文本(基础格式) |
| 主流播放器支持 | 较少 | 广泛支持 |
因此,当我们从专业字幕制作工具导出 USF 后,转 SRT 才能在视频播放器、剪辑软件、硬字幕工具中正常使用。
本文解决的核心问题
解析 USF 字幕
将时间转换为 SRT 格式
处理跨天字幕(24:00→00:00 的情况)
处理多 text 节点合并
确保字幕序号、文本、时长合法
一行代码调用完成转换
完整 Python 代码(USF → SRT)
import re
from pathlib import Path
import xml.etree.ElementTree as ET
def parse_hms_to_seconds(time_str: str) -> float:
m = re.match(r"^(\d{2}):(\d{2}):(\d{2})(?:\.(\d{1,3}))?$", time_str.strip())
if not m:
raise ValueError(f"Invalid time format: {time_str}")
h, mi, s, ms = m.groups()
hours = int(h)
minutes = int(mi)
seconds = int(s)
millis = int(ms) if ms is not None else 0
return hours * 3600 + minutes * 60 + seconds + millis / 1000.0
def format_seconds_to_srt(total_seconds: float) -> str:
total_ms = int(round(total_seconds * 1000))
hours = total_ms // 3_600_000
rem = total_ms % 3_600_000
minutes = rem // 60_000
rem = rem % 60_000
seconds = rem // 1000
millis = rem % 1000
return f"{hours:02d}:{minutes:02d}:{seconds:02d},{millis:03d}"
def clean_text(text: str) -> str:
t = text.replace("\r\n", "\n").replace("\r", "\n")
t = re.sub(r"\n{3,}", "\n\n", t)
return t.strip()
def convert_usf_to_srt(usf_path: Path, srt_path: Path | None = None) -> Path:
if srt_path is None:
srt_path = usf_path.with_suffix(".srt")
tree = ET.parse(usf_path)
root = tree.getroot()
subs_root = root.find(".//subtitles")
if subs_root is None:
raise ValueError("USF file missing <subtitles> section")
items = []
day_offset = 0
prev_base_start = None
for sub in subs_root.findall("subtitle"):
start_attr = sub.get("start")
stop_attr = sub.get("stop")
if not start_attr or not stop_attr:
continue
base_start = parse_hms_to_seconds(start_attr)
base_stop = parse_hms_to_seconds(stop_attr)
if prev_base_start is not None and base_start < prev_base_start:
day_offset += 1
start_seconds = base_start + day_offset * 86400
stop_seconds = base_stop + day_offset * 86400
if base_stop < base_start:
stop_seconds += 86400
texts = []
for tnode in sub.findall("text"):
content = "".join(tnode.itertext())
if content:
texts.append(clean_text(content))
text_joined = "\n".join([t for t in texts if t])
if not text_joined:
text_joined = ""
items.append((start_seconds, stop_seconds, text_joined))
prev_base_start = base_start
lines = []
for idx, (st, en, txt) in enumerate(items, start=1):
start_str = format_seconds_to_srt(st)
end_str = format_seconds_to_srt(en)
lines.append(str(idx))
lines.append(f"{start_str} --> {end_str}")
lines.append(txt)
lines.append("")
srt_path.write_text("\n".join(lines), encoding="utf-8")
return srt_path
def main():
usf_file = Path(r"20251120.usf")
out_file = Path(r"20251120.srt")
srt_path = convert_usf_to_srt(usf_file, out_file)
print(f"SRT written: {srt_path}")
if __name__ == "__main__":
main()
核心逻辑解析
USF 时间解析(带毫秒)
USF 中时间格式为:
HH:MM:SS.sss
使用正则解析并转换为秒:
parse_hms_to_seconds()
例如:
00:03:12.500 → 192.5 秒
防止跨天错误
有些字幕可能这样:
| 行 | start | stop |
|---|---|---|
| 1 | 23:59:55 | 23:59:58 |
| 2 | 00:00:02 | 00:00:06 |
看起来像倒退了,其实是跨天。
代码自动维护 day_offset,避免:
00:00:02 比 23:59:55 更早
合并多段文本内容
USF 一个 subtitle 下可能有多个 <text>,例如:
<subtitle start="00:03:00" stop="00:03:05">
<text>第一行</text>
<text>第二行</text>
</subtitle>
输出自动:
第一行
第二行
SRT 输出格式
符合标准:
序号
HH:MM:SS,mmm --> HH:MM:SS,mmm
字幕内容
如何使用?
1.将 .usf 放到脚本所在目录
2.修改:
usf_file = Path("example.usf")
3.运行:
python convert.py
生成:
example.srt
播放器、硬字幕工具立即可用。
到此这篇关于Python代码实现将USF字幕格式转换为SRT的文章就介绍到这了,更多相关Python USF字幕转SRT内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
为2021年的第一场雪锦上添花:用matplotlib绘制雪花和雪景
这篇文章主要介绍了为2021年的第一场雪锦上添花:用matplotlib绘制雪花和雪景,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧2021-01-01
Python logging管理不同级别log打印和存储实例
这篇文章主要介绍了Python logging管理不同级别log打印和存储实例,具有一定借鉴价值,需要的朋友可以参考下2018-01-01
django admin 自定义替换change页面模板的方法
今天小编就为大家分享一篇django admin 自定义替换change页面模板的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧2019-08-08
解决pyecharts运行后产生的html文件用浏览器打开空白
这篇文章主要介绍了解决pyecharts运行后产生的html文件用浏览器打开空白,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧2020-03-03


最新评论