Deutsch

Video & Untertitel · Untertitel-Toolkit

Wie ein Browser eine SRT-Datei analysiert: Blöcke, Indizes, Timecodes und Text

· Wie es funktioniert

Untertitel srt Dateiformate

Zwei SRT Cue-Blöcke, getrennt durch eine Leerzeile, jeweils mit einer Indexzeile, einer Timecode-Zeile und Textzeilen
Original-ToolAcre-Vektorillustration

SRT sieht trivial aus, bis Sie auf echte Dateien stoßen. In diesem Beitrag erfahren Sie, wie ein Parser Blöcke aufteilt, Indizes und Timecodes liest, mehrzeiligen Text verarbeitet und die fehlerhaften Blöcke, die in realen Dateien enthalten sind, wiederherstellt.

Die Datei „sieht gut aus“, aber die Hälfte der Hinweise fehlt – wie ein nachsichtig wirkendes Format strenge Erwartungen verbirgt

SRT hat keinen Spezifikationskörper, keine MIME-Registrierung und keinen Validator, der mit Spielern geliefert wird. Stattdessen existiert eine Form, auf die sich die meisten Softwareprogramme einigen: eine Zahl, eine Timecode-Zeile, eine oder mehrere Textzeilen und dann eine Leerzeile. Da die Form konventionell und nicht spezifiziert ist, können zwei Dateien in einem Texteditor beide korrekt aussehen, während nur eine von ihnen geladen wird, und der Fehler ist normalerweise still. Ein Spieler, der einen Cue nicht lesen kann, neigt dazu, ihn zu überspringen, anstatt ihn zu melden, sodass eine Datei mit einem defekten Block mit einer Lücke statt mit einem Fehler abgespielt wird.

Ein Parser hat also zwei Aufgaben, die in entgegengesetzte Richtungen ziehen. Es muss die Variationen akzeptieren, die echte Dateien enthalten, da Dateien von Transkriptionsdiensten, Handbearbeitungsdiensten und Formatkonvertern erstellt werden, die jeweils unterschiedliche Annahmen treffen. Es muss auch Messwerte ablehnen, die einen Hinweis zur falschen Zeit setzen würden, da ein stillschweigend falscher Zeitstempel schlimmer ist als ein gemeldeter Fehler.

Aufteilung in Blöcke – Leerzeilen als Trennzeichen und das Problem mit verstreuten Leerzeichen und CRLF

Die Aufteilung erfolgt bei Leerzeilen, nicht bei den Indexnummern. Der Parser normalisiert zunächst die Zeilenenden und ersetzt sowohl das CRLF-Paar als auch eine einzelne CR durch eine einzelne neue Zeile, da eine unter Windows erstellte und unter Unix bearbeitete Datei beides enthalten kann. Anschließend teilt es eine Reihe von zwei oder mehr Zeilenumbrüchen auf, schneidet jeden resultierenden Block ab und verwirft die leeren. Diese Reihenfolge ist wichtig: Eine Aufteilung vor der Normalisierung würde am Ende einer Timecode-Zeile zu einem fehlerhaften Wagenrücklauf führen, und der Timecode würde dann nicht übereinstimmen.

Vor all dem wird eine Byte-Reihenfolgemarkierung entfernt. Ein UTF-8 BOM am Anfang einer Datei besteht aus drei Bytes, die ein naiver Parser als Teil der ersten Indexnummer sieht, was ausreicht, um den ersten Cue unlesbar zu machen, während jeder spätere Cue analysiert wird. Nachgestellte Leerzeichen auf einer ansonsten leeren Trennlinie werden durch den Zuschnitt behandelt, sodass eine Datei, deren Leerzeilen ein Leerzeichen enthalten, trotzdem korrekt geteilt wird.

Die Indexzeile – warum Zahlen oft falsch sind, dupliziert werden oder fehlen und warum Parser ihnen nicht vertrauen sollten

Die Indexnummer wird gelesen und dann ignoriert. Echte Dateien nummerieren Stichwörter von Null an, starten die Nummerierung nach einer Zusammenführung neu, duplizieren eine Nummer nach einer manuellen Bearbeitung oder lassen die Zeile ganz weg, wenn ein Konverter die Datei geschrieben hat. Diesen Zahlen zu vertrauen bedeutet, dass jeder einzelne dieser Fehler geerbt wird. Daher weist der Parser stattdessen eine eigene fortlaufende Nummer zu und zählt die Hinweise, die er bisher erfolgreich erstellt hat.

Diese Wahl erklärt auch, warum der Parser niemals das Vorhandensein der Indexzeile erfordert. Es findet die Timecode-Zeile, indem es den Block nach der ersten Zeile mit dem Pfeil durchsucht, anstatt davon auszugehen, dass der Timecode die zweite Zeile ist. Ein Block ohne Indexzeile wird normal geparst, und ein Block mit zwei vereinzelten Zeilen vor dem Timecode wird trotzdem geparst, da die Position nicht das ist, was den Timecode identifiziert.

Die Timecode-Zeile – HH:MM:SS,mmm --> HH:MM:SS,mmm, tolerierte Variationen und diejenigen, die Spieler stören

Die Timecode-Zeile wird mit einem einzelnen regulären Ausdruck abgeglichen und die darin enthaltenen Toleranzen sind bewusst. Stunden sind optional, da WebVTT eine Zwei-Felder-Anzeige zulässt und von Konvertern ausgegeben wird. Als Millisekundentrennzeichen wird entweder ein Komma oder ein Punkt akzeptiert, unabhängig davon, welches Format die Datei angeblich hat, da gemischte Trennzeichen so häufig vorkommen, dass ihre Ablehnung mehr gute als schlechte Dateien zum Scheitern bringen würde. Nachkommastellen werden rechts aufgefüllt, sodass ein Cue, der mit einer einzelnen Ziffer endet, als Hunderte von Millisekunden und nicht als Einheiten gelesen wird.

Zwei Lesungen werden abgelehnt. Ein Minuten- oder Sekundenfeld über neunundfünfzig wird eher abgelehnt als übertragen, da neunzig Sekunden keine Uhrangabe sind und normalerweise auf eine beschädigte oder falsch konvertierte Datei hinweisen. Eine stille Normalisierung würde den Hinweis verschieben. Eine Zeile, deren Anfang oder Ende nicht geparst werden kann, führt zu einem aufgezeichneten Problem mit dem Namen des fehlerhaften Textes und der erwarteten Form, und der Block wird übersprungen und nicht erraten.

Textzeilen – mehrzeilige Hinweise, Formatierungs-Tags und wo ein Block wirklich endet

Alles nach der Timecode-Zeile ist der Cue-Text, der durch Zeilenumbrüche wieder zusammengefügt wird. Es gibt keine Zeilenbeschränkung und keinen Reflow-Versuch, sodass ein Cue mit drei Zeilen als drei Zeilen bestehen bleibt. Aus diesem Grund ist die Leerzeile lasttragend: Sie ist das Einzige, was dem Parser mitteilt, dass der Text zu Ende ist, weshalb ein Cue, dessen eigener Text eine Leerzeile enthält, als zwei Blöcke gelesen wird und die zweite Hälfte als ohne Timecode gemeldet wird.

Cue-Einstellungen werden vom Endzeitstempel durch eine Reihe von zwei oder mehr Leerzeichen getrennt. WebVTT ermöglicht Positionierungsanweisungen wie Ausrichtung und Zeilenplatzierung, die der Endzeit in derselben Zeile folgen, sodass der Parser sie abspaltet, bevor der Zeitstempel analysiert wird, und sie neben dem Hinweis behält. Ein einzelnes Leerzeichen ist kein Trennzeichen, das verhindert, dass eine lediglich unordentliche Timecode-Zeile ihre Endzeit verliert.

Arbeitsbeispiel: Parsen einer Fünf-Cue-Datei mit zwei absichtlichen Fehlern – was ein robuster Parser wiederherstellt und was er markiert

Nehmen Sie eine Datei mit fünf Blöcken, in der die Timecode-Zeile von Block drei beschädigt wurde, um 00:01:75,000 --> 00:01:78,000 zu lesen, und Block vier hat seine Timecode-Zeile beim Kopieren und Einfügen vollständig verloren. Der Parser liest die Blöcke eins und zwei normal und nummeriert sie eins und zwei. Block drei entspricht der Form eines Timecodes, enthält jedoch ein Sekundenfeld von fünfundsiebzig. Daher wird er abgelehnt und als fehlerhafter Zeitstempel mit der Bezeichnung der Zeile aufgezeichnet, die er nicht lesen konnte.

Block vier enthält überhaupt keinen Pfeil, daher wird er ohne Zeitstempel aufgezeichnet, wobei die ersten vierzig Zeichen des Blocks in Anführungszeichen gesetzt werden, damit die Zeile in der Originaldatei gefunden werden kann. Block fünf wird analysiert und wird zu Cue drei, nicht zu Cue fünf, da die Nummerierung erfolgreiche Cues zählt. Das Ergebnis sind drei verwendbare Hinweise und zwei spezifische, lokalisierte Beschwerden, statt einer Ausnahme beim ersten Fehler und keiner Information über den zweiten.

Was dies nicht abdeckt – ASS/SSA Styling, Positionierungscodes und Nicht-Untertiteltext, der in SRT abgelegt wird

Dies beschreibt SRT und die Teile von WebVTT, die seine Cue-Form teilen. Es deckt nicht ASS und SSA ab, die einen Skript-Header, Stildefinitionen und Stilreferenzen pro Ereignis enthalten und nicht durch Aufteilen in Leerzeilen gelesen werden können. Karaoke-Timing, Zeichenbefehle und die in diesen Formaten verwendeten Inline-Override-Tags liegen außerhalb der Modelle eines Cue- und Timecode-Parsers.

Text wird auch nicht repariert. Ein in eine Datei ohne Timecodes eingefügtes Transkript erzeugt eine Liste von Blöcken ohne Zeitstempel, die genau gemeldet werden, aber ohne fehlende Timing-Informationen nicht in Untertitel umgewandelt werden können. Kodierungsfehler sind ein separates Problem: Eine Datei, die mit dem falschen Zeichensatz dekodiert wurde, wird in vollkommen gültige Hinweise analysiert, deren Text falsch ist, und keine noch so umfassende Strukturprüfung kann dies erkennen.

Takeaway: Nachsichtig analysieren, streng schreiben – wie das Subtitle Toolkit chaotische SRT liest und eine saubere zurückschreibt

Die Arbeitsregel besteht darin, nachsichtig zu analysieren und streng zu schreiben. Akzeptieren Sie auf dem Weg dorthin optionale Stunden, Trennzeichen, fehlende Indexzeilen, gemischte Zeilenenden und eine führende Byte-Reihenfolgemarkierung und zeichnen Sie jeden Fehler als lokalisiertes Problem auf, anstatt ihn auf das erste zu werfen, damit eine Datei in einem einzigen Durchgang repariert werden kann. Geben Sie auf dem Weg nach draußen eine kanonische Form aus.

Das macht das Subtitle Toolkit bei der Konvertierung. Cues werden von eins an neu nummeriert und zusammenhängend gehalten, Zeitstempel werden mit einem Komma für SRT und einem Punkt für WebVTT erneut ausgegeben, und die zurückkommende Datei hat die von den Spielern erwartete Form, unabhängig davon, wie unregelmäßig die Eingabe war. Fügen Sie eine Datei, die ein Spieler abgelehnt hat, in den Konverter ein und lesen Sie zuerst die gemeldeten Probleme. Sie benennen das Stichwort und zitieren die Zeile, was normalerweise ausreicht, um den Fehler im Original zu finden.