ビデオと字幕 · 字幕ツールキット
ブラウザが SRT ファイルを解析する方法: ブロック、インデックス、タイムコード、テキスト
· 仕組み
字幕 srt ファイル形式
SRT は、実際のファイルに出会うまでは些細なことのように見えます。この投稿では、パーサーがどのようにブロックを分割し、インデックスとタイムコードを読み取り、複数行のテキストを処理し、実際のファイルに含まれる不正なブロックから回復するかを説明します。
ファイルは「正常に見えます」が、キューの半分が欠落しています — 寛容に見える形式がどのように厳密な期待を隠すか
SRT には仕様本体、MIME 登録、プレーヤーに同梱されるバリデータはありません。代わりに存在するのは、ほとんどのソフトウェアが同意する形状です。つまり、数字、タイムコード行、1 行以上のテキスト行、そして空白行です。形状は指定されたものではなく従来のものであるため、テキスト エディターでは 2 つのファイルがどちらか 1 つだけがロードされていても両方とも正しく表示され、通常はエラーは発生しません。キューを読み取ることができないプレーヤーは、キューを報告するのではなくスキップする傾向があるため、ブロックが壊れたファイルはエラーではなくギャップを持って再生されます。
したがって、パーサーには、反対方向にプルする 2 つのジョブがあります。実際のファイルに含まれるバリエーションを受け入れる必要があります。ファイルは、それぞれ異なる前提を置く転写サービス、手動編集、および形式コンバーターによって生成されるためです。また、サイレントに間違ったタイムスタンプは、報告された失敗よりも悪いため、間違ったタイミングで合図を与える読み取りを拒否する必要があります。
ブロックへの分割 - 区切り文字としての空白行と、迷走空白と CRLF の問題
分割はインデックス番号ではなく、空白行で発生します。 Windows で作成され Unix で編集されたファイルには両方が含まれる可能性があるため、パーサーは最初に行末を正規化し、CRLF ペアと単独の CR の両方を単一の改行に置き換えます。次に、2 つ以上の改行を実行して分割し、結果の各ブロックをトリミングして、空のブロックを破棄します。この順序が重要です。正規化する前に分割すると、タイムコード行の最後に改行が残り、タイムコードが一致しなくなります。
バイト オーダー マークは、これらの前に削除されます。ファイルの先頭にある UTF-8 BOM は 3 バイトで、単純なパーサーは最初のインデックス番号の一部として認識します。これは、後のすべてのキューを解析する間、最初のキューを読み取り不能にするのに十分です。空白の区切り行の末尾のスペースはトリムによって処理されるため、空白行にスペースが含まれるファイルでも正しく分割されます。
インデックス行 - 数値が間違っている、重複している、または欠落していることが多い理由と、パーサーが数値を信頼すべきではない理由
インデックス番号は読み取られ、その後無視されます。実際のファイルはキューにゼロから番号を付け、マージ後に番号付けを再開し、手動編集後に番号を複製するか、コンバーターがファイルを書き込んだときに行を完全に省略します。これらの数値を信頼するということは、それらの障害をすべて継承することを意味するため、パーサーは代わりに独自の連続番号を割り当て、これまでに正常に構築したキューをカウントします。
この選択は、パーサーがインデックス行の存在を決して要求しない理由も説明しています。タイムコードが 2 番目のラインであると想定するのではなく、ブロック内で矢印を含む最初のラインを検索することによって、タイムコード ラインを特定します。インデックス ラインのないブロックは通常どおり解析されますが、タイムコードの前に 2 本の迷走ラインがあるブロックは、位置によってタイムコードを識別するものではないため、引き続き解析されます。
タイムコード行 — HH:MM:SS,mmm --> HH:MM:SS,mmm、許容される変動とプレーヤーを破壊する変動
タイムコード行は単一の正規表現と照合され、その許容誤差は意図的に設定されています。 WebVTT では 2 フィールドの読み取りが許可されており、コンバーターはそれを出力するため、時間はオプションです。ファイルがどの形式であると主張しているかに関係なく、カンマまたはピリオドのいずれかがミリ秒の区切り文字として受け入れられます。区切り文字が混在しているのが一般的であるため、区切り文字を拒否すると、不良ファイルよりも良好なファイルの方が失敗する可能性が高くなります。小数点以下の数字は右側に埋め込まれるため、1 桁で終わるキューは単位ではなく数百ミリ秒として読み取られます。
2 つの読み取りが拒否されました。 90 秒は時計の読み取り値ではなく、通常はファイルが破損しているか誤って変換されていることを示すため、59 秒を超える分または秒のフィールドは転送されずに拒否されます。ノーマライズするとキューが移動します。行の開始または終了が解析に失敗すると、問題のあるテキストと予想される形状の名前を示す記録された問題が生成され、ブロックは推測されずにスキップされます。
テキスト行 - 複数行のキュー、書式設定タグ、およびブロックが実際に終了する場所
タイムコード行以降はすべて、改行で結合されたキュー テキストです。ライン制限はなく、リフローも試行されないため、3 ラインのキューは 3 ラインとして残ります。これが、空白行が負荷に耐える理由です。空白行は、テキストが終了したことをパーサーに伝える唯一のものです。そのため、テキスト自体に空白行が含まれるキューは 2 ブロックとして読み取られ、後半にはタイムコードがないと報告されます。
キュー設定は、終了タイムスタンプから 2 つ以上のスペースで区切られます。 WebVTT を使用すると、位置合わせや行の配置などのディレクティブを同じ行の終了時刻に従うことができるため、パーサーはタイムスタンプが解析される前にディレクティブを分割し、キューの横に保持します。単一のスペースは区切り文字ではないため、単なる乱雑なタイムコード行が終了時間を失わないようにすることができます。
実用的な例: 2 つの意図的な障害がある 5 つのキュー ファイルを解析する - 堅牢なパーサーが何を回復し、何をフラグするか
5 ブロックのファイルを考えます。このファイルでは、ブロック 3 のタイムコード ラインが破損しており、00:01:75,000 --> 00:01:78,000 を読み取り、ブロック 4 はコピー アンド ペースト中にタイムコード ラインが完全に失われています。パーサーは通常、ブロック 1 と 2 を読み取り、それらに 1 と 2 の番号を付けます。ブロック 3 はタイムコードの形状と一致しますが、秒フィールドが 75 であるため、ブロック 3 は拒否され、読み取れなかった行を示す不正なタイムスタンプとして記録されます。
ブロック 4 には矢印がまったく含まれていないため、タイムスタンプなしとして記録され、ブロックの最初の 40 文字が引用され、元のファイルでその行を見つけることができます。番号付けでは成功したキューがカウントされるため、5 つの解析をブロックすると、キュー 5 ではなくキュー 3 になります。その結果、最初の障害については例外が発生し、2 番目の障害については情報が得られず、3 つの使用可能な手がかりと 2 つの特定の苦情が得られます。
これでカバーされないもの — ASS/SSA スタイル、位置コード、および SRT にダンプされる字幕以外のテキスト
これは、SRT とそのキュー形状を共有する WebVTT の部分について説明します。 ASS と SSA はカバーされていません。これらはスクリプト ヘッダー、スタイル定義、イベントごとのスタイル参照を持ち、空行で分割して読み取ることができません。カラオケのタイミング、描画コマンド、およびこれらの形式で使用されるインライン オーバーライド タグは、キューとタイムコードのパーサーのモデルの範囲外です。
また、テキストは修復されません。タイムコードのないファイルに貼り付けられたトランスクリプトは、タイムスタンプのないブロックのリストを生成します。これは正確に報告されますが、存在しないタイミング情報なしでは字幕に変換できません。エンコーディングの誤りは別の問題です。間違った文字セットでデコードされたファイルは、テキストが間違っている完全に有効なキューに解析され、いくら構造チェックを行ってもそれを検出できません。
要点: 解析は寛大に、書き込みは厳密に行う — 字幕ツールキットが乱雑な SRT をどのように読み取り、クリーンな文字列を書き戻すか
作業ルールは、寛大に解析し、厳密に記述することです。途中で、オプションの時間、区切り文字、インデックス行の欠落、行末の混合、および先頭のバイト オーダー マークを受け入れ、最初の障害をスローするのではなく、すべての障害を特定の問題として記録します。これにより、ファイルを 1 回のパスで修正できます。途中で、標準シェイプを 1 つ放出します。
これが、字幕ツールキットが変換時に行うことです。キューは 1 から番号が付け直されて連続性が保たれ、タイムスタンプは SRT の場合はカンマ、WebVTT の場合はピリオドを使用して再発行され、入力がどれほど不規則であったとしても、返されるファイルはプレーヤーが期待する形状になります。プレーヤーが拒否したファイルをコンバーターに貼り付け、最初に報告された問題を読みます。彼らはキューに名前を付け、その行を引用します。通常、オリジナルの欠陥を見つけるにはこれで十分です。