python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Python USF字幕转SRT

Python代码实现将USF字幕格式转换为SRT

作者:林九生

在影音处理、字幕整理、视频本地化等场景中,我们经常会遇到不同字幕格式需要互转的情况,其中USF是一种基于 XML 的字幕格式,下面我们就来看看具体实现方法吧

字幕处理:USF 字幕格式转换为 SRT

在影音处理、字幕整理、视频本地化等场景中,我们经常会遇到不同字幕格式需要互转的情况,其中 USF(Universal Subtitle Format) 是一种基于 XML 的字幕格式,而 SRT(SubRip Subtitle)则是最常见、最被播放器和编辑软件支持的格式。

本文分享一段 实战 Python 代码,完成 USF → SRT 转换,并对处理流程、注意事项、关键逻辑逐行解析,开箱即用。

USF 与 SRT 有什么区别

特性USFSRT
结构基于 XML文本文件
时间格式HH:MM:SS.sssHH: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 秒

防止跨天错误

有些字幕可能这样:

startstop
123:59:5523:59:58
200:00:0200: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内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文