解析.srt文件

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了解析.srt文件相关的知识,希望对你有一定的参考价值。

1
00:00:00,074 --> 00:00:02,564
Previously on Breaking Bad...

2
00:00:02,663 --> 00:00:04,393
Words...

我需要用php解析srt文件并用变量打印文件中的所有subs。

我找不到合适的reg exps。当这样做时,我需要采用id,时间和字幕变量。并且当打印时,不存在array()s等等必须与原始文件中的相同。

我的意思是我必须打印出来;

$number <br> (e.g. 1)
$time <br> (e.g. 00:00:00,074 --> 00:00:02,564)
$subtitle <br> (e.g. Previously on Breaking Bad...)

顺便说一句,我有这个代码。但它没有看到线条。它必须编辑,但如何?

$srt_file = file('test.srt',FILE_IGNORE_NEW_LINES);
$regex = "/^(d)+ ([d]+:[d]+:[d]+,[d]+) --> ([d]+:[d]+:[d]+,[d]+) (w.+)/";

foreach($srt_file as $srt){

    preg_match($regex,$srt,$srt_lines);

    print_r($srt_lines);
    echo '<br />';

}
答案

这是一个简短的状态机,用于逐行解析SRT文件:

define('SRT_STATE_SUBNUMBER', 0);
define('SRT_STATE_TIME',      1);
define('SRT_STATE_TEXT',      2);
define('SRT_STATE_BLANK',     3);

$lines   = file('test.srt');

$subs    = array();
$state   = SRT_STATE_SUBNUMBER;
$subNum  = 0;
$subText = '';
$subTime = '';

foreach($lines as $line) {
    switch($state) {
        case SRT_STATE_SUBNUMBER:
            $subNum = trim($line);
            $state  = SRT_STATE_TIME;
            break;

        case SRT_STATE_TIME:
            $subTime = trim($line);
            $state   = SRT_STATE_TEXT;
            break;

        case SRT_STATE_TEXT:
            if (trim($line) == '') {
                $sub = new stdClass;
                $sub->number = $subNum;
                list($sub->startTime, $sub->stopTime) = explode(' --> ', $subTime);
                $sub->text   = $subText;
                $subText     = '';
                $state       = SRT_STATE_SUBNUMBER;

                $subs[]      = $sub;
            } else {
                $subText .= $line;
            }
            break;
    }
}

if ($state == SRT_STATE_TEXT) {
    // if file was missing the trailing newlines, we'll be in this
    // state here.  Append the last read text and add the last sub.
    $sub->text = $subText;
    $subs[] = $sub;
}

print_r($subs);

结果:

Array
(
    [0] => stdClass Object
        (
            [number] => 1
            [stopTime] => 00:00:24,400
            [startTime] => 00:00:20,000
            [text] => Altocumulus clouds occur between six thousand
        )

    [1] => stdClass Object
        (
            [number] => 2
            [stopTime] => 00:00:27,800
            [startTime] => 00:00:24,600
            [text] => and twenty thousand feet above ground level.
        )

)

然后,您可以循环遍历subs数组或通过数组偏移量访问它们:

echo $subs[0]->number . ' says ' . $subs[0]->text . "
";

通过循环遍历每个潜在客户并显示它来显示所有潜艇:

foreach($subs as $sub) {
    echo $sub->number . ' begins at ' . $sub->startTime .
         ' and ends at ' . $sub->stopTime . '.  The text is: <br /><pre>' .
         $sub->text . "</pre><br />
";
}

进一步阅读:SubRip Text File Format

另一答案

这是不匹配的,因为你的$ srt_file数组可能如下所示:

Array
([0] => '1',
[1] => '00:00:00,074 --> 00:00:02,564',
[2] => 'Previously on Breaking Bad...'.
[3] => '',
[4] => '2',
...
)

你的正则表达式不会匹配任何这些元素。

如果你的意图是将整个文件读入一个长字符串的内存中,那么使用file_get_contents将整个文件内容整合到一个字符串中。然后使用preg_match_all获取所有正则表达式匹配。

否则,您可能会尝试遍历数组并尝试匹配各种正则表达式模式,以确定该行是id,时间范围还是文本,并做适当的事情。很明显,您可能还需要一些逻辑来确保以正确的顺序获取值(id,然后是时间范围,然后是文本)。

另一答案

使用file()array_chunk()数组分组为4块,然后省略最后一个条目,因为它是一个如下所示的空白行:

foreach( array_chunk( file( 'test.srt'), 4) as $entry) {
    list( $number, $time, $subtitle) = $entry;
    echo $number . '<br />';
    echo $time . '<br />';
    echo $subtitle . '<br />';
}
另一答案

我创建了一个类来将.srt文件转换为数组。数组的每个条目都具有以下属性:

  • if:表示字幕id的数字(2)
  • start:float,以秒为单位的开始时间(24.443)
  • 结束:浮动,结束时间(秒)(27.647)
  • startString:人类可读格式的开始时间(00:00:24.443)
  • endString:人类可读格式的结束时间(00:00:24.647)
  • duration:字幕的持续时间,以ms为单位(3204)
  • 文字:副标题的文字(孔雀统治了贡门市。)

代码是php7:

<?php

namespace VideoSubtitlesSrt;


class SrtToArrayTool
{


    public static function getArrayByFile(string $file): array
    {

        $ret = [];

        $gen = function ($filename) {
            $file = fopen($filename, 'r');
            while (($line = fgets($file)) !== false) {
                yield rtrim($line);
            }
            fclose($file);
        };

        $c = 0;
        $item = [];
        $text = '';
        $n = 0;
        foreach ($gen($file) as $line) {

            if ('' !== $line) {
                if (0 === $n) {
                    $item['id'] = $line;
                    $n++;
                }
                elseif (1 === $n) {
                    $p = explode('-->', $line);
                    $start = str_replace(',', '.', trim($p[0]));
                    $end = str_replace(',', '.', trim($p[1]));
                    $startTime = self::toMilliSeconds(str_replace('.', ':', $start));
                    $endTime = self::toMilliSeconds(str_replace('.', ':', $end));
                    $item['start'] = $startTime / 1000;
                    $item['end'] = $endTime / 1000;
                    $item['startString'] = $start;
                    $item['endString'] = $end;
                    $item['duration'] = $endTime - $startTime;
                    $n++;
                }
                else {
                    if ($n >= 2) {
                        if ('' !== $text) {
                            $text .= PHP_EOL;
                        }
                        $text .= $line;
                    }
                }
            }
            else {
                if (0 !== $n) {
                    $item['text'] = $text;
                    $ret[] = $item;
                    $text = '';
                    $n = 0;
                }
            }
            $c++;
        }
        return $ret;
    }


    private static function toMilliSeconds(string $duration): int
    {
        $p = explode(':', $duration);
        return (int)$p[0] * 3600000 + (int)$p[1] * 60000 + (int)$p[2] * 1000 + (int)$p[3];
    }


}

或者在这里查看:https://github.com/lingtalfi/VideoSubtitles

另一答案

您可以使用此项目:https://github.com/captioning/captioning

示例代码:

<?php
require_once __DIR__.'/../vendor/autoload.php';

use CaptioningFormatSubripFile;

try {
    $file = new SubripFile('your_file.srt');

    foreach ($file->getCues() as $line) {
        echo 'start: ' . $line->getStart() . "<br />
";
        echo 'stop: ' . $line->getStop() . "<br />
";
        echo 'startMS: ' . $line->getStartMS() . "<br />
";
        echo 'stopMS: ' . $line->getStopMS() . "<br />
";
        echo 'text: ' . $line->getText() . "<br />
";
        echo "=====================<br />
";
    }

} catch(Exception $e) {
    echo "Error: ".$e->getMessage()."
";
}

样本输出:

> php index.php
start: 00:01:48,387<br />
stop: 00:01:53,269<br />
startMS: 108387<br />
stopMS: 113269<br />
text: ┘ç┘à╪د┘ç┘┌»█î ╪▓█î╪▒┘┘ê█î╪│ ╪ذ╪د ┌ر█î┘█î╪ز ╪ذ┘┘ê╪▒█î ┘ê ┌ر╪»┌ر x265
=====================<br />
start: 00:02:09,360<br />
stop: 00:02:12,021<br />
startMS: 129360<br />
stopMS: 132021<br />
text: .┘à╪د ┘╪ذ╪د┘è╪» ╪ز┘┘ç╪د┘è┘è ╪د┘è┘╪ش╪د ╪ذ╪د╪┤┘è┘à -
┌╪▒╪د ╪ا<br />
=====================<br />
start: 00:02:12,022<br />
stop: 00:02:14,725<br />
startMS: 132022<br />
stopMS: 134725<br />
text: ..╪د┌»┘ç ┘╛╪»╪▒╪ز -
.╪د┘ê┘ ┘ç┘è┌┘ê┘é╪ز ┘à╪ز┘ê╪ش┘ç ╪▒┘╪ز┘┘à┘ê┘ ┘┘à┘è╪┤┘ç -<br />
=====================<br />
另一答案

它可以通过使用php换行来完成。我能成功地让我显示我的代码

$srt=preg_split("/\r\n\r\n/",trim($movie->SRT));
            $result[$i]['IMDBID']=$movie->IMDBID;
            $result[$i]['TMDBID']=$movie->TMDBID;

这里$ movie-> SRT是在这个问题中

以上是关于解析.srt文件的主要内容,如果未能解决你的问题,请参考以下文章

解析.srt文件

使用 Objective C 解析 SRT 文件

公网传输技术之SRT协议解析(上)

公网传输技术之SRT协议解析(下)

音频和视频流最佳选择?SRT 协议解析及报文识别

正则表达式 处理srt