原文を損なわずにSRT字幕の文字エンコーディングを修正する方法
文字化けしたSRTテキストの原因を特定し、デコードエラーと文字欠落を区別した上で、安全なPythonツールと再現可能なサンプルを使って別のUTF-8コピーを作成します。

SRT字幕で café の代わりに caféと表示されている場合、すぐにファイルをUTF-8として保存し直さないでください。まずはバイトデータをそのまま保持したコピーを残し、正しい語句に復元できるデコード方式を特定してから、検証済みのテキストを別ファイルに書き出す必要があります。誤った文字のまま新しいエンコーディングで保存してしまうと、文字化けした状態が固定されてしまいます。
重要なのは、 有効なエンコーディングであることと、正しいテキストであることの違いです。以下の2つのキューを用いた検証実験では、破損した一方のファイルは厳格なUTF-8チェックを通過し、置換文字も含まれていませんが、フランス語のテキストとしては誤ったままです。もう一方のファイルも同じチェックを通過しますが、元の6文字が次の文字に置き換わってしまっています: �.
本ガイドでは、 ローカルで動作するPythonの検査・変換ツール、ダウンロード可能なソースファイル、そして再現可能なテストを提供します。対象とするのはファイルレベルの診断と明示的な変換であり、エンコーディングの自動検出や動画との同期調整、欠落した文字の完全な復元を保証するものではありません。
まずは何が破損しているのかを特定する
拡張子の .srt は字幕フォーマットを示すものに過ぎず、特定のエンコーディングを保証するものではありません。SRTにはキュー番号、タイムスタンプ、テキスト、区切り文字が含まれており、米国議会図書館の SRTフォーマット仕様レコード でも、単一の文字エンコーディング規格を持たないプレーンテキストとして説明されています。
目に見える症状は調査を開始するきっかけとして捉え、それだけで原因を断定しないでください。
| 表示される症状 | 確認すべき点 | 次にとるべき適切な手順 |
|---|---|---|
| 特定のアプリでアクセント記号や特殊記号が正しく表示されない | 変更を加えていない元のファイルを既知のソースエンコーディングで再度開くと、正しいテキストが表示されますか? | 正しいテキストが表示される場合は、そのデコード方式を明示的に指定して新しいコピーを書き出します。 |
café UTF-8として正常に読み込まれたファイルに依然として残っている | 以前にUTF-8が別のエンコーディングとして誤って読み取られ、そのまま保存されていませんか? | 元のバイトデータに戻るか、正確な変換履歴を調査してください。単にUTF-8で再度保存しても修復にはなりません。 |
� 文字や記号があるべき場所に表示される | ファイル内に実際にU+FFFDが保存されているのか、それとも現在のアプリがデコードできないバイトを表示する際に挿入しているだけですか? | 手を加えていない元のソースを確認してください。保存されてしまった置換文字から元の文字を特定することはできません。 |
| プレーヤーでは豆腐(四角形)が表示されるが、信頼できるテキストビューアでは本来の文字が表示される | 基盤となるコードポイントは正しいですか?プレーヤーは同じファイルを読み込んでいますか? | ファイルを変更する前に、プレーヤーのデコード設定、フォントの文字対応状況、またはレンダリング設定を調査してください。 |
文字とその表示形状は別物です。Pythonの Unicode解説 では、コードポイントとフォントによってレンダリングされるグリフを明確に区別しています。エディタ上でテキストが正しく表示される場合、プレーヤー側の問題である可能性が高いですが、特定のフォントをインストールすれば解決するという保証はありません。この記事では個別のフォントやプレーヤーの検証は行っていません。
バイトデータをバックアップし、デコード状態を確認する
をダウンロードし、 subtitle_encoding.py 調査したいSRTファイルと同じフォルダに配置します。これらのコマンドを実行するにはPython 3がインストールされている必要がありますが、追加のパッケージは不要です。ここでのローカル検証にはmacOS上のPython 3.14.3を使用しました。Windows環境でPythonランチャーを使用している場合は、 py -3 を python3に置き換えてください(その環境でのテストは行っていません)。
そのフォルダでターミナルを開きます。以下の例では、 input.srt を実際のファイル名に置き換えてください。スペースを含むパスは引用符で囲んだままにしてください。
変更を加えていないバックアップコピーを作成する
python3 subtitle_encoding.py backup "input.srt" "original-bytes.srt"
保存先ファイルは事前に存在していてはなりません。このツールはデコードを行わずにバイトデータをそのままコピーし、コピーした内容を再読み込みしてSHA-256ハッシュを報告します。また、コピー元と同じパスを指定した場合は拒否されます。使用可能な字幕ファイルを作成した後も、このバックアップは保持してください。
何も保存せずにUTF-8を確認する
python3 subtitle_encoding.py inspect "original-bytes.srt"
レポートには、 strict_utf8, utf8_bom、選択されたデコード方式、そしてそのデコードが成功した場合はテキストのプレビューと replacement_characters のカウントを含めます。デフォルトのテキストビューでは utf-8-sigが使用され、先頭のUTF-8署名(BOM)が処理されます。
strict_utf8: falseは、バイト列がUTF-8の検証に失敗したことを意味します。他のどのエンコーディングが正しいかを教えてくれるわけでは ありません 。strict_utf8: trueは、UTF-8としてデコードできることを意味します。ただし、単語が正しく復元されていることを意味するわけでは ありません 。- 置換文字のカウントがゼロでない場合は、選択したデコードによってU+FFFD文字が生成されたことを示します。新しいファイルを作成する前に、それらの箇所を調査してください。
検証結果はASCIIセーフなJSON形式で出力されるため、ターミナルのフォントによって文字の正体が隠れることはありません。 \u00e9 は éを意味し、 \ufffd は置換文字を意味します。疑わしい行を詳細に調べるには、キュー番号ではなく、物理的な行番号を指定してください。
python3 subtitle_encoding.py inspect "original-bytes.srt" --encoding cp1252 --line 3
これは Windows-1252(Pythonの cp1252 コーデック)の読み取り専用テストです。この例でたまたまフランス語が使われていたからではなく、エクスポート設定やソースの履歴からその選択が裏付けられる場合に使用してください。行レポートには各文字の名前とコードポイントが表示されます。 U+20AC はユーロ記号です。
最初にプレビューが成功したものではなく、根拠に基づいてエンコーディングを選択する
ファイルの作成者に実際のエクスポートエンコーディングを問い合わせるか、エクスポート元アプリケーションの設定を確認するか、信頼できる元の文字起こしテキストと比較してください。ファイル全体を通して、アクセント付きの名前、句読点、通貨記号、代表的な行を確認します。その言語が読めない場合、デコードに成功したとしても、ツールが代わりにその確認を行ってくれるわけではありません。
「ANSI」という呼称は、ソースコーデックを特定するには曖昧すぎます。また、Windows-1252とLatin-1も互換性があるわけではありません。提示された実験では、単一バイトの 80 は € では cp1252にデコードされますが、制御文字の U+0080 としてデコードされ、 latin-1では別の文字列になります。どちらの処理も成功するため、どちらが意図されたものかは元のソース情報からしか判断できません。
他の言語では別のレガシーエンコーディングが使われている可能性がありますが、言語名だけでエンコーディングが一意に決まるわけではありません。作成経緯が不明で候補となる読み取り結果が一致しない場合は、変換作業を中断し、より確実なソース情報を確認してください。
ソーステキストが読める状態になってから変換する
Windows-1252であることが確認できたソースに対しては、別のUTF-8ファイルを生成します。
python3 subtitle_encoding.py convert "original-bytes.srt" "repaired-utf8.srt" --from-encoding cp1252
python3 subtitle_encoding.py inspect "repaired-utf8.srt"
この変換ツールは、ソース全体を厳格にデコードし、そのテキストをUTF-8としてエンコードした上で、出力のデコード結果が同一テキストに戻るかを検証し、書き込まれたバイト列を再読込して確認します。キュー番号、タイムスタンプ、台詞、タグ、改行コードの編集は一切行われません。デコードされたテキストが同一であっても、新しいバイトシーケンスは異なる場合があります。
意図的に以下の処理は行いません。
- 既存の出力先ファイルの上書き
- 厳格なデコードエラーを無視して処理を続行すること
- U+FFFDが含まれるテキストの書き込み(その文字が意図的なものであったとしても)
最後の制限は安全性を考慮したものです。このツールでは置換文字が元々何を表していたかを判断できません。コマンドを通すためにそれを除去することは、テキストを復元しているのではなく証拠を破棄していることになります。Pythonの エラーハンドラーのドキュメント では、 replace や ignore が厳格なデコードとどのように異なるかが説明されています。これらは問題のあるデータを置き換えるか破棄するため、この変換手順では使用すべきではありません。
I/Oエラーが発生した場合は、失敗した出力ファイルを使用しないでください。不完全な 新しい ファイルが残る可能性があるため、元のファイルはそのまま保持し、再試行する際は新しい出力先ファイル名を指定してください。ツールの詳細な動作や使い方は、 ダウンロード可能なREADME.
BOM付きUTF-8はどう扱うべきか?
UTF-8のBOMは、先頭のバイトシーケンス EF BB BFです。Pythonの utf-8-sig コーデック は、デコード時にこのシグネチャを消費し、エンコード時に付加します。
BOM付きのUTF-8ソースであることが確認できている場合は、 --from-encoding utf-8-sigを使用してください。このツールは通常、BOMなしのUTF-8を出力します。 --with-bom を追加するのは、受け取り側のアプリケーションの要件で求められている場合のみにしてください。BOMを変更しても、 café を caféに変えることはできません。なお、この実験は特定のプレーヤー、エディター、またはアップロードプラットフォームとの互換性を保証するものではありません。
UTF-8としての妥当性だけでは不十分であることを示す5つの小さなファイル
この実験では、完全に自作したフランス語の字幕キュー2つを使用しています。これらは映画、顧客データ、または翻訳製品から引用したものではありません。
1
00:00:01,000 --> 00:00:04,000
Émile dit : « Le prix est de 12,50 €. »
2
00:00:05,000 --> 00:00:08,000
Le café est fermé.
2026年9月13日、Python 3.14.3の標準ライブラリスクリプトを使用して5つのバイト表現を生成し、それぞれを既知のソースと比較しました。これらは決定論的なバイトおよび文字列の検証であり、翻訳品質のベンチマークではありません。ブラウザのプレビューをコピーするのではなく、リンク先のファイルをディスクに保存してください。異なるバイト列そのものがこの実験の要点だからです。
| ダウンロード可能なファイル | バイト数 | 厳密なUTF-8か? | UTF-8としてデコードした際に正しいテキストになるか? | UTF-8テキスト内にU+FFFDを保持しているか |
|---|---|---|---|---|
| オリジナルのUTF-8 | 132 | はい | はい | 0 |
| オリジナルのWindows-1252 | 125 | いいえ | UTF-8としてデコード不可。以下では正しく表示: cp1252 | 該当なし |
| 誤ったデコーダーでUTF-8として再保存 | 147 | はい | いいえ | 0 |
| 置換文字を含んでUTF-8として再保存 | 137 | はい | いいえ | 6 |
| 正しく変換されたUTF-8 | 132 | はい | はい | 0 |
どのコピーでも、同じ2つのタイムスタンプ文字列が保持されています。正しく変換されたファイルは、元のUTF-8ファイルとバイト単位で完全に一致します。破損した2つのUTF-8ファイルは、限定的ではあるものの有用な事実を証明しています。エンコーディングが有効であることも、タイムスタンプが変更されていないことも、字幕テキストが正しいことの証明にはならないということです。また、タイムスタンプが一致しているからといって、この作成されたトラックが実際の動画と同期しているかどうかもわかりません。
これら5つのファイルをご自身で再現するには、 reproduce.py をダウンロードし、存在しないディレクトリ名を指定して実行してください。
python3 reproduce.py encoding-experiment
このスクリプトはフィクスチャファイルと、全文、変換処理、ハッシュ値、ランタイムバージョン、およびアサーションを含む results.json を出力します。これを 記録された実験結果と比較してください(生成タイムスタンプのみ異なります)。スクリプトと元の教育用ファイルには MITライセンス.
ローカルコンバーターの検証では、既存の出力ファイルの上書き拒否、ソースパスの検証、誤ったコーデックによる失敗、U+FFFDの拒否、CRLFの維持、明示的なBOM出力もテストされています。これらの検証はこのツールのファイル動作を確認するものであり、プレーヤーでのレンダリング、実際のメディアとのタイミング、またはBookTranslatorによる翻訳をテストするものではありません。
文字化けしたまま保存されてしまった場合
保存された文字化け:正確な経緯を調査する
今回の文字化けの例は、既知の一連の流れをたどっています。元のUTF-8バイト列がWindows-1252としてデコードされ、その誤った文字がUTF-8として保存されました。その結果、 café や、壊れたユーロ記号の並びである €.
この特定の変換ではバイト列の欠損がなかったため、再現スクリプトで元に戻すことができます。誤ったテキストを cp1252で再エンコードし、得られたバイト列をUTF-8としてデコードするのです。スクリプトは、復元されたテキストが元のテキストと一致するか検証します。
これはあくまで この既知の経緯に対する証明であり、あらゆるSRTファイルに包括的な「文字化け修復」処理を一律に適用することを推奨するものではありません。ファイルには正当な文字や、複数の経緯の混在、あるいは過去の修復によってすでに変更されたテキストが含まれている可能性があります。手を加えていない元ファイルと通常の変換手順を優先してください。保存された文字化けファイルしか残っていない場合は、それを原本として保管した上で、別のコピーに対して逆変換を試みる前に、どのように発生したかを特定してください。
保存された置換文字:失われた文字はそこにはエンコードされていません
このデータ損失のサンプルは、Windows-1252バイトを置換文字を有効にした状態でUTF-8としてデコードし、その結果を保存して作成されたものです。異なる元の文字がすべて同じ � マーカーに置き換わってしまいました。保存されたマーカーには、その位置に元々どの文字が存在していたかを特定できるだけの情報が残っていません。
これを、アプリ内で単に 見えているだけ � の状態と混同しないでください。元のバイトデータがそのまま保持されていれば、今回のWindows-1252ソースのように、正しいデコードによってテキストを復元できる可能性があります。データが失われたと判断する前に、まずは元のソースを確認してください。
手元に残っている唯一のファイルで欠落テキストがすでにU+FFFDや文字通りの疑問符に置き換わってしまっている場合は、クリーンなソースを再エクスポートまたは再取得するか、信頼できる資料と照らし合わせて手動で文字起こしを検証してください。通常の疑問符は正規の句読点である場合もあるため、存在していること自体は何の証明にもなりません。AIモデルによるそれらしい置換はあくまで推測であり、復元されたファイルデータではありません。
コマンドの成功だけでなく、読めるソースに仕上がっているか確認する
修復したファイルを採用する前に、代表的な単語や記号を信頼できるソースと比較し、キュー番号やタイムスタンプの行が変わっていないことを確認したうえで、 新しいファイル を実際に使用するアプリケーションで開いてみてください。スクリプトはデコードされたテキストを保持するだけであり、SRT構文の検証ツールや再生の受け入れテストではありません。
字幕が正しく読めるようになり、他の言語が不要であれば作業は完了です。動画と合わせた確認やさらなる編集が必要な場合は、 字幕ソフトの比較 で各ツールの役割を解説しています。
原文テキストの信頼性が確保され、かつ別の言語が必要な場合にのみ、 BookTranslatorの字幕翻訳機能 や AI字幕翻訳ワークフローに進んでください。エンコーディングの修復、翻訳、そして最終トラックの視聴確認は別々の作業として扱いましょう。どれか1つが成功したからといって、他も成功した証拠にはなりません。





