3 Stimmen

Wie finde ich alle Vorkommen einer Zeichenfolge, der eine bestimmte Zeichenkette vorausgeht?

Ich versuche, alle Übereinstimmungen aus einer EBML-Definition zu extrahieren, die in etwa wie folgt aussieht:

| + A track
|  + Track number: 3
|  + Track UID: 724222477
|  + Track type: subtitles
...
|  + Language: eng
...
| + A track
|  + Track number: 4
|  + Track UID: 745646561
|  + Track type: subtitles
...
|  + Language: jpn
...

Ich möchte alle Vorkommen von "Sprache: ???", wenn davor "Track type: subtitles" steht. Ich habe mehrere Varianten ausprobiert:

Track type: subtitles.*Language: (\w\w\w)

Ich verwende den Mehrzeilenmodifikator in Ruby, damit er mit Zeilenumbrüchen übereinstimmt (wie der 's'-Modifikator in anderen Sprachen).

Dies funktioniert, um die zuletzt Vorkommen, was im obigen Beispiel beispielsweise "jpn" wäre:

string.scan(/Track type: subtitles.*Language: (\w\w\w)/m)
=> [["jpn"]]

Das Ergebnis würde ich gerne sehen:

=> [["eng"], ["jpn"]]

Was wäre eine korrekte Regex, um dies zu erreichen?

7voto

Paige Ruten Punkte 164391

Sie müssen Ihre Regex nicht gierig machen, indem Sie dies ändern:

.*

Zu diesem:

.*?

Ihr Regex passt ab dem ersten Vorkommen von Track type: subtitles bis zum letzten Vorkommen von Language: (\w\w\w) . Es funktioniert, wenn man es nicht gierig macht, weil es mit so wenigen Zeichen wie möglich übereinstimmt.

3voto

Markus Jarderot Punkte 83090

Sie müssen einen "Lazy Quantifier" anstelle von .* . Versuchen Sie dies:

/Track type: subtitles.*?Language: (\w\w\w)/m

Damit sollten Sie das erste Vorkommen von " Language: ??? " nach jedem " Track type: subtitles: ". Es würde jedoch verwirren, wenn eine Spur (vom Typ subtitles ) würde die Language Feld.


Eine andere Möglichkeit wäre, dies zu tun:

/^\| \+ (?:(?!^\| \+).)*?\+  Track type: subtitles$(?:(?!^\| \+).)*?^\|  \+ Language: (\w+)$/m

Sieht zwar etwas chaotisch aus, sollte aber das Problem mit der vorherigen Version beheben.


Eine sauberere Methode wäre die Tokenisierung der Zeichenfolge:

/^\| \+ ([^\r\n]+)|^\|  \+ Track type: (subtitles)|^\|  \+ Language: (\w+)/m

(Achten Sie auf die Anzahl der Leerzeichen)

Für jede Übereinstimmung prüfen Sie, welche der definierten Erfassungsgruppen vorhanden ist. Für jeden einzelnen Treffer kann nur eine Gruppe einen Wert haben.

  • Wenn es sich um die erste Gruppe hat ein neuer Weg begonnen. Verwerfen Sie alle gespeicherten Informationen über den vorherigen Titel.
  • Wenn es sich um die zweite Gruppe, ist der aktuelle Track vom Typ subtitles .
  • Wenn es sich um die dritte Gruppe ist die Sprache dieses Titels zu finden.
  • Wann immer Sie die Sprache eines Tracks kennen und wissen, dass er vom Typ subtitles melden Sie es.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X