最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python代碼實(shí)現(xiàn)將USF字幕格式轉(zhuǎn)換為SRT

 更新時(shí)間:2026年03月04日 09:16:42   作者:林九生  
在影音處理、字幕整理、視頻本地化等場(chǎng)景中,我們經(jīng)常會(huì)遇到不同字幕格式需要互轉(zhuǎn)的情況,其中USF是一種基于 XML 的字幕格式,下面我們就來(lái)看看具體實(shí)現(xiàn)方法吧

字幕處理:USF 字幕格式轉(zhuǎn)換為 SRT

在影音處理、字幕整理、視頻本地化等場(chǎng)景中,我們經(jīng)常會(huì)遇到不同字幕格式需要互轉(zhuǎn)的情況,其中 USF(Universal Subtitle Format) 是一種基于 XML 的字幕格式,而 SRT(SubRip Subtitle)則是最常見(jiàn)、最被播放器和編輯軟件支持的格式。

本文分享一段 實(shí)戰(zhàn) Python 代碼,完成 USF → SRT 轉(zhuǎn)換,并對(duì)處理流程、注意事項(xiàng)、關(guān)鍵邏輯逐行解析,開(kāi)箱即用。

USF 與 SRT 有什么區(qū)別

特性USFSRT
結(jié)構(gòu)基于 XML文本文件
時(shí)間格式HH:MM:SS.sssHH:MM:SS,mmm
支持樣式字體、大小、顏色等豐富信息純文本(基礎(chǔ)格式)
主流播放器支持較少廣泛支持

因此,當(dāng)我們從專業(yè)字幕制作工具導(dǎo)出 USF 后,轉(zhuǎn) SRT 才能在視頻播放器、剪輯軟件、硬字幕工具中正常使用。

本文解決的核心問(wèn)題

解析 USF 字幕

將時(shí)間轉(zhuǎn)換為 SRT 格式

處理跨天字幕(24:00→00:00 的情況)

處理多 text 節(jié)點(diǎn)合并

確保字幕序號(hào)、文本、時(shí)長(zhǎng)合法

一行代碼調(diào)用完成轉(zhuǎn)換

完整 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 時(shí)間解析(帶毫秒)

USF 中時(shí)間格式為:

HH:MM:SS.sss

使用正則解析并轉(zhuǎn)換為秒:

parse_hms_to_seconds()

例如:

00:03:12.500 → 192.5 秒

防止跨天錯(cuò)誤

有些字幕可能這樣:

startstop
123:59:5523:59:58
200:00:0200:00:06

看起來(lái)像倒退了,其實(shí)是跨天。

代碼自動(dòng)維護(hù) day_offset,避免:

00:00:02 比 23:59:55 更早

合并多段文本內(nèi)容

USF 一個(gè) subtitle 下可能有多個(gè) <text>,例如:

<subtitle start="00:03:00" stop="00:03:05">
    <text>第一行</text>
    <text>第二行</text>
</subtitle>

輸出自動(dòng):

第一行
第二行

SRT 輸出格式

符合標(biāo)準(zhǔn):

序號(hào)
HH:MM:SS,mmm --> HH:MM:SS,mmm
字幕內(nèi)容

如何使用?

1.將 .usf 放到腳本所在目錄

2.修改:

usf_file = Path("example.usf")

3.運(yùn)行:

python convert.py

生成:

example.srt

播放器、硬字幕工具立即可用。

到此這篇關(guān)于Python代碼實(shí)現(xiàn)將USF字幕格式轉(zhuǎn)換為SRT的文章就介紹到這了,更多相關(guān)Python USF字幕轉(zhuǎn)SRT內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • PyTorch中torch.argmax函數(shù)的使用

    PyTorch中torch.argmax函數(shù)的使用

    torch.argmax 是一個(gè)高效的工具,廣泛應(yīng)用于分類模型預(yù)測(cè)、指標(biāo)計(jì)算等場(chǎng)景,下面就來(lái)介紹一下PyTorch中torch.argmax函數(shù)的使用,感興趣的可以了解一下
    2025-05-05
  • python使用writerows寫(xiě)csv文件產(chǎn)生多余空行的處理方法

    python使用writerows寫(xiě)csv文件產(chǎn)生多余空行的處理方法

    這篇文章主要介紹了python使用writerows寫(xiě)csv文件產(chǎn)生多余空行的處理方法,需要的朋友可以參考下
    2019-08-08
  • Python3 數(shù)據(jù)結(jié)構(gòu)示例詳解

    Python3 數(shù)據(jù)結(jié)構(gòu)示例詳解

    本文介紹了Python中的四種基本數(shù)據(jù)結(jié)構(gòu)——列表、元組、集合和字典,以及如何根據(jù)具體需求選擇合適的數(shù)據(jù)結(jié)構(gòu),文章還展示了如何使用這些數(shù)據(jù)結(jié)構(gòu)進(jìn)行基本操作,并提供了示例代碼,感興趣的朋友跟隨小編一起看看吧
    2025-11-11
  • python中startswith()和endswith()的用法詳解

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

    Python startswith() 方法用于檢查字符串是否是以指定子字符串開(kāi)頭,endswith()方法主要是用于判斷字符串是否以指定字符或子字符串結(jié)尾,常用于判斷文件類型,對(duì)python startswith()和endswith()用法相關(guān)知識(shí)感興趣的朋友一起看看吧
    2021-10-10
  • Python?IDLE設(shè)置清屏快捷鍵的方法詳解

    Python?IDLE設(shè)置清屏快捷鍵的方法詳解

    這篇文章主要為大家詳細(xì)介紹了Python?IDLE設(shè)置清屏快捷鍵的方法,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,感興趣的可以了解一下
    2022-09-09
  • pytorch中的自定義數(shù)據(jù)處理詳解

    pytorch中的自定義數(shù)據(jù)處理詳解

    今天小編就為大家分享一篇pytorch中的自定義數(shù)據(jù)處理詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-01-01
  • flask中獲取各種請(qǐng)求數(shù)據(jù)的常見(jiàn)方法小結(jié)

    flask中獲取各種請(qǐng)求數(shù)據(jù)的常見(jiàn)方法小結(jié)

    在 Flask 里,能使用多種方法獲取不同類型的請(qǐng)求數(shù)據(jù),這篇文章為大家詳細(xì)介紹了Flask中常見(jiàn)請(qǐng)求數(shù)據(jù)的獲取方式,有需要的小伙伴可以參考一下
    2025-06-06
  • Python讀取csv、Excel文件生成圖表的方法

    Python讀取csv、Excel文件生成圖表的方法

    這篇文章主要介紹了Python讀取csv、Excel文件生成圖表,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-07-07
  • 利用scrapy將爬到的數(shù)據(jù)保存到mysql(防止重復(fù))

    利用scrapy將爬到的數(shù)據(jù)保存到mysql(防止重復(fù))

    這篇文章主要給大家介紹了關(guān)于利用scrapy將爬到的數(shù)據(jù)保存到mysql(防止重復(fù))的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看看吧。
    2018-03-03
  • PyTorch一小時(shí)掌握之圖像識(shí)別實(shí)戰(zhàn)篇

    PyTorch一小時(shí)掌握之圖像識(shí)別實(shí)戰(zhàn)篇

    這篇文章主要介紹了PyTorch一小時(shí)掌握之圖像識(shí)別實(shí)戰(zhàn)篇,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-09-09

最新評(píng)論

东方市| 阿拉善左旗| 贺州市| 宝兴县| 彭州市| 阳朔县| 通州市| 九江市| 惠水县| 新和县| 连江县| 海安县| 台中县| 永济市| 白水县| 红桥区| 西昌市| 合山市| 灯塔市| 常州市| 合水县| 务川| 湟中县| 新和县| 安化县| 阿合奇县| 武强县| 华池县| 嘉荫县| 太保市| 博兴县| 襄樊市| 东明县| 汾阳市| 扶绥县| 新野县| 吴江市| 琼海市| 兴安县| 格尔木市| 岱山县|