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

 更新时间:2026年03月04日 09:16:42   作者:林九生  
在影音处理、字幕整理、视频本地化等场景中,我们经常会遇到不同字幕格式需要互转的情况,其中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内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • PyTorch中torch.argmax函数的使用

    PyTorch中torch.argmax函数的使用

    torch.argmax 是一个高效的工具,广泛应用于分类模型预测、指标计算等场景,下面就来介绍一下PyTorch中torch.argmax函数的使用,感兴趣的可以了解一下
    2025-05-05
  • python使用writerows写csv文件产生多余空行的处理方法

    python使用writerows写csv文件产生多余空行的处理方法

    这篇文章主要介绍了python使用writerows写csv文件产生多余空行的处理方法,需要的朋友可以参考下
    2019-08-08
  • Python3 数据结构示例详解

    Python3 数据结构示例详解

    本文介绍了Python中的四种基本数据结构——列表、元组、集合和字典,以及如何根据具体需求选择合适的数据结构,文章还展示了如何使用这些数据结构进行基本操作,并提供了示例代码,感兴趣的朋友跟随小编一起看看吧
    2025-11-11
  • python中startswith()和endswith()的用法详解

    python中startswith()和endswith()的用法详解

    Python startswith() 方法用于检查字符串是否是以指定子字符串开头,endswith()方法主要是用于判断字符串是否以指定字符或子字符串结尾,常用于判断文件类型,对python startswith()和endswith()用法相关知识感兴趣的朋友一起看看吧
    2021-10-10
  • Python IDLE设置清屏快捷键的方法详解

    Python IDLE设置清屏快捷键的方法详解

    这篇文章主要为大家详细介绍了Python IDLE设置清屏快捷键的方法,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的可以了解一下
    2022-09-09
  • pytorch中的自定义数据处理详解

    pytorch中的自定义数据处理详解

    今天小编就为大家分享一篇pytorch中的自定义数据处理详解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-01-01
  • flask中获取各种请求数据的常见方法小结

    flask中获取各种请求数据的常见方法小结

    在 Flask 里,能使用多种方法获取不同类型的请求数据,这篇文章为大家详细介绍了Flask中常见请求数据的获取方式,有需要的小伙伴可以参考一下
    2025-06-06
  • Python读取csv、Excel文件生成图表的方法

    Python读取csv、Excel文件生成图表的方法

    这篇文章主要介绍了Python读取csv、Excel文件生成图表,本文通过示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-07-07
  • 利用scrapy将爬到的数据保存到mysql(防止重复)

    利用scrapy将爬到的数据保存到mysql(防止重复)

    这篇文章主要给大家介绍了关于利用scrapy将爬到的数据保存到mysql(防止重复)的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
    2018-03-03
  • PyTorch一小时掌握之图像识别实战篇

    PyTorch一小时掌握之图像识别实战篇

    这篇文章主要介绍了PyTorch一小时掌握之图像识别实战篇,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-09-09

最新评论