AIでSRT字幕の固有名詞を直すときは、字幕番号とタイムコードを固定し、修正する本文だけを受け取ると確認しやすい。動画編集で困るのは、誤字を直したつもりが、表示時間や字幕の区切りまで変わることだ。全文の作り直しを避け、変更する番号を指定する。
この記事では「AIが修正候補を提案→人が採用→Pythonで本文だけ置換」という独自の手順を紹介する。掲載コードは合成したSRTで8種類のテストを実行済みだ。実際の音声認識精度や、DaVinci Resolveへの取り込みを実機測定した結果ではない。
用意する3つのファイル
| ファイル | 役割 | 触らないもの |
|---|---|---|
| original.srt | 書き出した字幕の原本 | 字幕番号・開始終了時刻 |
| dictionary.txt | 人名・商品名の正しい表記 | 根拠のない言い換え |
| corrections.json | 採用した番号と本文の対応 | 未採用の修正 |
1
00:00:01,000 --> 00:00:03,000
クロードで編集する。
2
00:00:03,500 --> 00:00:05,000
Beeperを使う。
修正から再取り込みまでの手順
- 編集ソフトからSRTを書き出し、original.srtとして保存する。原本は上書きしない。
- 固有名詞の辞書を用意する。聞き取れない人名は録音や台本で確認する。
- AIへ番号・本文・辞書を渡し、修正候補と理由だけを作らせる。
- 採用する修正をcorrections.jsonへ転記する。AIが出した理由やコードフェンスは入れない。
- 以下のスクリプトをsrt_patch.pyとして保存し、別名のfixed.srtを作る。
- 原本と修正版の時刻が一致することを確認し、編集ソフトへ取り込む。修正した区間を音声と合わせて再生する。
DaVinci ResolveはSRTなどの字幕ファイルの読み込み・書き出しに対応する。対応形式の説明はBlackmagic Design公式の字幕機能を参照できる。字幕ファイルの編集と、Studioの自動文字起こし機能の利用条件は分けて確認する。
採用した本文だけを反映するコード
Python 3で動く標準ライブラリだけの例だ。コマンドは3ファイルのある作業フォルダーで実行する。出力先が既に存在すると停止するため、再試行時はfixed-v2.srtなど別名にする。
{"1": "Claudeで編集する。"}
python3 srt_patch.py original.srt corrections.json fixed.srt
検証済みのsrt_patch.pyを表示
"""Apply reviewed cue-text corrections without rewriting SRT timecodes."""
import json
import re
import sys
from pathlib import Path
TIME = r"\d{2}:\d{2}:\d{2},\d{3}"
CUE = re.compile(rf"(\d+)(\r?\n)({TIME} --> {TIME})(\r?\n)([\s\S]+)")
def unique_object(pairs):
result = {}
for key, value in pairs:
if key in result:
raise ValueError(f"duplicate correction ID: {key}")
result[key] = value
return result
def millis(value):
h, m, rest = value.split(":")
s, ms = rest.split(",")
if int(m) > 59 or int(s) > 59:
raise ValueError("invalid timestamp")
return ((int(h) * 60 + int(m)) * 60 + int(s)) * 1000 + int(ms)
def patch(original, corrections):
if not isinstance(corrections, dict):
raise ValueError("corrections must be an object")
parts = re.split(r"(\r?\n[ \t]*\r?\n)", original)
seen = set()
for index in range(0, len(parts), 2):
if not parts[index].strip():
continue
match = CUE.fullmatch(parts[index])
if not match:
raise ValueError("unsupported or malformed SRT cue")
cue_id, nl, timing, _, body = match.groups()
if cue_id in seen:
raise ValueError(f"duplicate SRT ID: {cue_id}")
seen.add(cue_id)
start, end = timing.split(" --> ")
if millis(start) >= millis(end):
raise ValueError(f"invalid duration: {cue_id}")
if cue_id in corrections:
value = corrections[cue_id]
if not isinstance(value, str) or not value.strip():
raise ValueError(f"empty correction: {cue_id}")
value = value.replace("\r\n", "\n")
if "\r" in value or re.search(r"\n[ \t]*\n|-->|```", value):
raise ValueError(f"invalid correction: {cue_id}")
tail = nl if body.endswith(nl) else ""
parts[index] = match.group(0)[:match.start(5)] + value.rstrip("\n").replace("\n", nl) + tail
if not seen:
raise ValueError("no cues")
if set(corrections) - seen:
raise ValueError("unknown correction IDs")
return "".join(parts)
def main():
source, edits, target = map(Path, sys.argv[1:])
with source.open(encoding="utf-8-sig", newline="") as f:
original = f.read()
corrections = json.loads(edits.read_text(encoding="utf-8-sig"), object_pairs_hook=unique_object)
result = patch(original, corrections)
with target.open("x", encoding="utf-8", newline="") as f:
f.write(result)
print(f"saved: {target}; corrected cues: {len(corrections)}")
if __name__ == "__main__":
main()
確認できたことと対象外
| テスト | 結果 |
|---|---|
| 指定本文のみ置換 | 番号・タイムコード・対象外の字幕を維持 |
| CRLFと複数行の字幕 | 時刻行と改行形式を維持して置換 |
| 存在しない番号 | 出力前に拒否 |
| SRT番号の重複 | 拒否 |
| JSONキーの重複 | 拒否 |
| 空欄・空行・時刻矢印・コードフェンスを含む修正 | 拒否 |
| 終了が開始以前の時刻 | 拒否 |
| 修正なし | 本文を変えずに返す |
音声を聞いていないため、語句の正しさはコードでは判定できない。字幕間の重なり、読みやすい文字数、話者の切り替わりも人が確認する。この例は「番号→標準の時刻行→本文」の基本SRT向けで、独自の座標情報付き時刻行などは受け付けない。UTF-8で保存し、元ファイルの文字コードが違う場合は先に変換する。
作業に使える依頼文6例
1.辞書を作る
From this approved script, list exact spellings of product names and people. Do not infer spellings from sound alone.
2.候補だけ出す
Review the supplied numbered subtitle text using the dictionary. Return cue ID, original text, proposed text, and reason. Do not change timing or split cues.
3.曖昧さを残す
List uncertain words with cue IDs for human listening. Do not replace ambiguous names with a guess.
4.JSONを作る
For approved cue IDs only, return one JSON object mapping string cue IDs to replacement text. No markdown fences, comments, timestamps, or extra keys.
5.差分を確認
Compare original.srt and fixed.srt. Verify cue IDs and timing lines match exactly. Report every changed caption text and any unexpected structural change.
6.再生確認表
Create a listening checklist for the changed cue IDs. Include adjacent cues and checks for meaning, pronunciation, line length, and speaker continuity.
よくある質問
AIにSRT全文を直させてよいか
全文の生成では時間や区切りが変わることがある。原本を固定し、修正本文の対応表を使うと変更箇所を確認しやすい。
字幕のタイミングも直せるか
このコードの対象外だ。タイミング変更は編集ソフトで別工程として行う。
同じ名前が何度も出たら一括置換でよいか
文脈によって別人・別商品を指す場合がある。字幕番号ごとの候補を確認して採用する。
fixed.srtが既にあるというエラーが出たら
原本や前の成果物を保護するための停止だ。新しい出力名で実行する。
字幕の修正だけで編集が完成するか
映像・音声・字幕の同期確認は残る。全体の工程はDaVinci ResolveとClaudeの編集ワークフローを参照できる。
小さく始める3ステップ
- 今日:記事の入力例を、自分の仕事1件に置き換えて準備する。
- 今週:確認担当を決め、下書きと実際の原本を照合して1件を完了させる。
- 来月:手戻り、確認時間、失敗件数を振り返り、対象を広げるか判断する。
出典・検証範囲
確認日:2026年10月31日。掲載Pythonコードの8種類のテストを合成SRTで実行し、成功・拒否条件を確認した。実際の録音の認識精度や編集ソフトへの読み込みは未検証。画面名、提供地域、料金、接続条件は変更されるため、導入時は公式案内を再確認する。
企画の参考:Nagomi-ke:動画編集ワークフロー。動画内の利用成果を編集部の実績として扱っていない。
LIFRELLへの相談
AIに渡す資料、担当者の確認、成果物の保存まで含めた業務フローの設計は、LIFRELLの無料相談で相談できる。
