Как найти все вхождения последовательности символов, если ей предшествует определенная строка? - PullRequest
3 голосов
/ 06 ноября 2008

Я пытаюсь извлечь все совпадения из определения EBML, которое выглядит примерно так:

| + 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
...

Я хочу, чтобы все вхождения "Language: ???" когда ему предшествует "Тип трека: субтитры". Я попробовал несколько вариантов этого:

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

Я использую многострочный модификатор в Ruby, чтобы он соответствовал символам новой строки (как модификатор 's' в других языках).

Это работает для получения последнего вхождения, которое в приведенном выше примере будет 'jpn', например:

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

Результат, который я хотел бы:

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

Что было бы правильным регулярным выражением для достижения этой цели?

Ответы [ 2 ]

7 голосов
/ 06 ноября 2008

Вы должны сделать свое регулярное выражение не жадным, изменив это:

.*

К этому:

.*?

Ваше регулярное выражение совпадает с первого вхождения Track type: subtitles до последнего вхождения Language: (\w\w\w). Если вы сделаете его не жадным, это сработает, потому что оно соответствует как можно меньшему числу символов.

3 голосов
/ 06 ноября 2008

Вам нужно использовать ленивый квантификатор вместо .*. Попробуйте это:

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

Это должно дать вам первое вхождение «Language: ???» после каждого «Track type: subtitles:». Но это может привести к путанице, если какой-нибудь трек (типа subtitles) пропустит поле Language.


Другой способ сделать это будет:

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

Выглядит несколько грязно, но следует позаботиться о проблеме с предыдущей.


Более понятный способ - токенизировать строку:

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

(обратите внимание на количество пробелов)

Для каждого совпадения вы проверяете, какие из групп захвата определены. Только одна группа будет иметь какое-либо значение для любого совпадения.

  • Если это группа первая , начинается новый трек. Отменить любую сохраненную информацию о предыдущем треке.
  • Если это группа секунда , текущий трек имеет тип subtitles.
  • Если это третья группа, язык этой дорожки найден.
  • Если вам известен язык дорожки и ее тип subtitles, сообщите об этом.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...