декодирование данных временной метки vtt

#php #preg-match

#php #предварительное совпадение

Вопрос:

У меня есть несколько сотен строк, поступающих из файла субтитров VTT, пример из заголовка

 00:01:03.500 --> 00:01:03.510 align:start position:0%
<c.colorCCCCCC>fourth guess it came from a broken</c><c.colorE5E5E5> home
 </c>

00:01:03.510 --> 00:01:08.140 align:start position:0%
<c.colorCCCCCC>fourth guess it came from a broken</c><c.colorE5E5E5> home
a<00:01:04.580><c> father</c><00:01:05.580><c> not</c><00:01:05.820><c> being</c><00:01:05.880><c> there</c><00:01:06.890><c> my</c><00:01:07.890><c> mother</c></c>

00:01:08.140 --> 00:01:08.150 align:start position:0%
a<c.colorE5E5E5> father not being there my mother
 </c>

00:01:08.150 --> 00:01:13.429 align:start position:0%
a<c.colorE5E5E5> father not being there my mother</c>
<c.colorE5E5E5>getting<00:01:09.150><c> married</c><00:01:09.630><c> and</c><00:01:11.360><c> the</c><00:01:12.360><c> abuse</c></c><c.colorCCCCCC><00:01:12.659><c> started</c><00:01:13.049><c> at</c></c>

00:01:13.429 --> 00:01:13.439 align:start position:0%
<c.colorE5E5E5>getting married and the abuse</c><c.colorCCCCCC> started at
 </c>
  

Файлы субтитров VTT довольно запутанны, но цель состоит в том, чтобы захватить все слова в тегах временной метки и сами временные метки.
Я думал о предварительном совпадении, но не знаю, как этого добиться

 $pattern = "<([^;]*)>";
preg_match_all($pattern, $lineContent, $allintag);
  

Это то, что я получил, но остановился на этом.

 array(
00:01:03.510,
00:01:04.580,
00:01:05.58,
00:01:05.820,
00:01:05.880,
00:01:06.890,
00:01:07.890,
00:01:08.140,
00:01:09.150,
00:01:09.630,
00:01:11.360,
00:01:12.360,
00:01:12.659,
00:01:13.049
)
array(
'fourth guess it came from a broken home',
'father',
'not',
'being',
'there',
'my',
'mother',
'getting',
'married',
'and',
'the',
'abuse',
'started',
'at'
)
  

Комментарии:

1. Попробуйте preg_match_all('~<(?<time>d{2}:d{2}:d{2}.d )>|<c>s*(?<text>.*?)</c>~', $lineContent, $allintag)

2. На полпути это возвращает массив только с временными кодами, а не со словами между одним тегом временного кода и следующим

3. Смотрите демонстрацию PHP и демонстрацию регулярных выражений .

4. Работает как шарм

5. Или, может быть 3v4l.org/00WmD лучше

Ответ №1:

Вы можете использовать

 '~<(?<time>d{2}:d{2}:d{2}.d )><c>s*(?<text>.*?)</c>~'
  

Если временные и текстовые группы не являются последовательными, используйте

 '~<(?<time>d{2}:d{2}:d{2}.d )>|<c>s*(?<text>.*?)</c>~'
  

Смотрите демонстрацию регулярных выражений.

Подробные сведения

  • < < символ
  • (?<time>d{2}:d{2}:d{2}.d ) — Группа «время»: 2 цифры, : , 2 цифры, : , 2 цифры, . и затем 1 цифры
  • > > символ
  • <c> — буквенный <c> текст
  • s* — 0 пробелов
  • (?<text>.*?) — Группа «текст»: любые символы 0 , отличные от символов разрыва строки, как можно меньше
  • </c> — буквенный </c> текст.

Смотрите демонстрацию PHP:

 $lineContent = "<00:01:13.650><c> time</c><00:01:13.920><c> and</c> 
 <00:01:14.780><c> that's</c><00:01:15.780><c> what</c>";
if (preg_match_all('~<(?<time>d{2}:d{2}:d{2}.d )><c>s*(?<text>.*?)</c>~', $lineContent, $allintag)) {
    print_r($allintag["time"]);
    print_r($allintag["text"]);
}
  

Вывод:

 Array ( [0] => 00:01:13.650 [1] => 00:01:13.920 [2] => 00:01:14.780 [3] => 00:01:15.780 )
Array ( [0] => time [1] => and  [2] => that's  [3] => what )
  

Комментарии:

1. Хорошо, он все еще пропускает несколько слов. Смотрите отредактированный код

2. @PeterFriedlander Попробуйте '~<(?<time>d{2}:d{2}:d{2}.d )>|<c(?:.color(?:[a-fA-F0-9]{2}){3})?>s*(?<text>.*?)</c>~s' , посмотрите эту демонстрацию

3. Спасибо! Но я вставил формулу в код регулярного выражения и даже в демонстрационную ссылку, но она неправильно форматируется.

4. @PeterFriedlander У вас рекурсивная структура в ваших данных. Следовательно, неясно, что вам нужно получить. Пожалуйста, объясните, какой результат вы хотите получить.