Как разобрать файл субтитров .srt

Я пытаюсь загрузить и проанализировать файл субтитров .srt в VB.net. Это очень простой текстовый файл, но у меня возникли трудности.

Вот структура:

Hide   Copy Code
1
00:00:01,600 --> 00:00:04,200
English (US)

2
00:00:05,900 --> 00:00:07,999
This is a subtitle in American English
Sometimes subtitles have 2 lines

3
00:00:10,000 --> 00:00:14,000
Adding subtitles is very easy to do

  • Число
  • Затем следует время начала и окончания
  • за которым следует текст, который может состоять из 1 или нескольких строк

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

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

После прочтения файла .srt узнать «длину» файла .srt во времени, то есть последний временной код. В приведенном выше примере это будет: 00:00:14,000, когда субтитры отображаются в последний раз.


person jimmy398439    schedule 13.12.2019    source источник
comment
Привет и добро пожаловать в SO! Не могли бы вы обновить свой пост, указав, что вы пробовали, что не работает и ожидаемый результат, чтобы мы могли вам помочь.   -  person zaggler    schedule 13.12.2019


Ответы (4)


Вы можете легко сделать это с помощью LINQ и File.Readlines

Dim SrtTimeCode As String = ""
Dim lastTimeLine As String = File.ReadLines(FILE_NAME) _
    .LastOrDefault(Function(s) s.Contains(" --> "))

If lastTimeLine IsNot Nothing Then
    SrtTimeCode = lastTimeLine.Split(New String() {" --> "}, StringSplitOptions.None)(1)
End If

Обратите внимание, что File.ReadLines сохраняет в памяти только текущую строку при перечислении строк. Он не сохраняет весь файл. Это лучше масштабируется с большими файлами.

person Olivier Jacot-Descombes    schedule 15.12.2019

Комментарии и пояснения в режиме онлайн.

Private Sub OpCode()
    'Using Path.Combine you don't have to worry about if the backslash is there or not
    Dim theFile1 = Path.Combine(Application.StartupPath(), ListBox1.SelectedItem.ToString)
    'A streamreader needs to be closed and disposed,File.ReadAllLines opens the file, reads it, and closes it.
    'It returns an array of lines
    Dim lines = File.ReadAllLines(theFile1)
    Dim LastLineIndex = lines.Length - 1
    Dim lastLine As String = lines(LastLineIndex)
    'You tried to parse the entire line. You only want the first character
    Do Until Integer.TryParse(lastLine.Substring(0, 1), Nothing)
        LastLineIndex -= 1
        lastLine = lines(LastLineIndex)
    Loop
    'The lower case c tells the compiler that the preceding string is really a Char.
    Dim splitLine = lastLine.Split(">"c)
    'Starting at index 1 because there is a space between > and 0
    Dim SrtEndTimeCode As String = splitLine(1).Substring(1, 12)
    MessageBox.Show(SrtEndTimeCode)
End Sub
person Mary    schedule 14.12.2019

Кроме того, этого можно добиться с помощью регулярных выражений

Imports System.IO
Imports System.Text.RegularExpressions
'...

Private Sub TheCaller()
    Dim srtFile As String = "English.srt"
    Dim endTime = "Not Found!"

    If File.Exists(srtFile) Then
        Dim patt As String = ">.(\d\d:\d\d:\d\ds?,s?\d{3})"
        'Get the last match, --> 00:00:14,000 in your example:
        Dim lastMatch = File.ReadLines(srtFile).
            LastOrDefault(Function(x) Regex.IsMatch(x, patt))

        If lastMatch IsNot Nothing Then
            endTime = Regex.Match(lastMatch, patt).Groups(1).Value
        End If
    End If

    Console.WriteLine(endTime)
End Sub

Вывод regex101:

00:00:14,000

Если вы хотите избавиться от миллисекундной части, используйте вместо этого следующий шаблон:

Dim patt As String = ">.(\d\d:\d\d:\d\d)"

и вы получите regex101:

00:00:14
person Community    schedule 15.12.2019
comment
Ух ты ! потрясающие вещи! - person jimmy398439; 17.12.2019

Ну, думаю, я понял - это, вероятно, не лучший код, но он работает:

Вот что происходит в коде: У меня есть список с файлами .srt. Код берет файл .srt и помещает его в текстовое поле. дополнительные разрывы строк в конце файла и т. д. Затем он ищет первую строку, которая имеет только целое число (имеется в виду последняя строка), затем он ищет строку после той, которая является временным кодом, затем он берет часть справа, которая является конечный код И это "длина" файла .srt

   Dim appPath As String = Application.StartupPath() ' app path
        Dim theFile1 As String

        theFile1 = appPath & "\" & ListBox1.SelectedItem.ToString 'this is where i have the .srt files

        Dim FILE_NAME As String = theFile1

        Dim TextLine As String

        If System.IO.File.Exists(FILE_NAME) = True Then

            Dim objReader As New System.IO.StreamReader(FILE_NAME)

            Do While objReader.Peek() <> -1

                TextLine = TextLine & objReader.ReadLine() & vbNewLine

            Loop

            TextBox7.Text = TextLine ' load .srt into textbox

        Else

            MessageBox.Show("File Does Not Exist")

        End If
        Dim SrtTimeCode As String
        SrtTimeCode = ""

        If TextBox7.Lines.Any = True Then ' only execute if textbox has lines

            Dim lastLine As String

            For i = 1 To 20 'Check from the end of text file back 20 lines for final subtitle chunk
                lastLine = TextBox7.Lines(TextBox7.Lines.Length - i)

                If Integer.TryParse(lastLine, vbNull) Then   ' if the last line is found

                    SrtTimeCode = TextBox7.Lines(TextBox7.Lines.Length - i + 1) 'the last timecode has been found - now it needs to be split

                    GoTo TheEnd
                End If


            Next i
        End If


theEnd:
        Dim ChoppedSRTTimeCodeFinal As String
        Dim test As String = SrtTimeCode
        Dim ChoppedSRTTimeCode As String = test.Substring(test.IndexOf(">"c) + 1)


        'ChoppedSRTTimeCodeFinal = ChoppedSRTTimeCode.Substring(test.IndexOf(","c) + 1)
        ChoppedSRTTimeCodeFinal = ChoppedSRTTimeCode.Substring(0, ChoppedSRTTimeCode.IndexOf(","))

        MsgBox(ChoppedSRTTimeCodeFinal) ' this is the final timecode parsed
person jimmy398439    schedule 13.12.2019
comment
Вы действительно не должны злоупотреблять элементами управления как переменными. - person Olivier Jacot-Descombes; 15.12.2019