1

我从字幕文件 (.srt) 创建了一个列表,其中每一行都在列表的索引内。现在我想删除一些行,特别是以“xx:xx:xx,xxx --> xx:xx:xx,xxx”格式的时间间隔开头的行。我做了一些研究(好吧,对一个复杂的主题进行了相当肤浅的研究,我可能会补充)并尝试创建以下子:

Private Shared Sub listCleaning(ByRef sList As List(Of String))
    For Each line As String In sList
        Dim pattern As String = "\b\d\d:\d\d:\d\d:\d\d,\d\d\d --> \b\d\d:\d\d:\d\d:\d\d,\d\d\d"
        Dim reg As New Regex(pattern)

        If line = "" Or Integer.TryParse(line, Nothing) Or reg.IsMatch(pattern) Then
            sList.Remove(line)
        End If
    Next
End Sub

现在我有两个问题:

  1. 我的正则表达式没有被正确解析。
  2. 当我的 If Block 上的条件有效并且该行被删除时,由于列表已更改,因此在单击 next 时会出现 InvalidOperationException。

谁能帮我写一个正确的正则表达式和一种遍历列表的方法来删除不需要的行?

tnx 提前。

编辑:

好的,Tim 解决了大部分问题,但我仍然需要一个适合“xx:xx:xx,xxx --> xx:xx:xx,xxx”模式的正则表达式。有人愿意关心吗?

提前致谢!

4

2 回答 2

1

这些是我对您的原始代码所做的更改。

首先,我不使用 for each 循环,而是更传统的 for 循环
第二,反向循环,所以你的删除到列表的末尾
第三,正则表达式模式应该在循环之外

Private Shared Sub listCleaning(ByRef sList As List(Of String)) 
    Dim pattern As String = "\d{2}:\d{2}:\d{2},\d{3}\s+-->\s+\d{2}:\d{2}:\d{2},\d{3}" 
    Dim reg As New Regex(pattern) 
    Dim x as Integer
    For x = sList.Count - 1 to 0 step -1
        Dim line as string = sList(x)
                Console.WriteLine(line)
        If line = "" Or Integer.TryParse(line, Nothing) Or reg.IsMatch(line) Then 
               sList.Remove(line) 
        End If 
    Next 
End Sub 

这是我的测试数据:

Sub Main
    Dim sList as List(Of String) = new List(Of string)
    sList.Add("01:01:01,003 --> 02:02:02,003")
    sList.Add("sdsdfsdfsd03 --> 02:02:02,003")
    sList.Add("03:01:01,003 --> 03:02:02,003")
    sList.Add("04:01:01,003 --> 04:02:02,003")
    sList.Add("05:01:01,003 --> 05:02:02,003")
    sList.Add("06:01:01,003 --> 06:02:02,003")
    sList.Add("07:01:01,003 --> 07:02:02,003")
    sList.Add("08:01:01,003 --> 08:02:02,003")
    sList.Add("09:01:01,003 --> 02:02:02 003")    

    console.WriteLine("Call listCleaning with " + sList.Count.ToString +  " elements")

    listCleaning(sList)

    console.WriteLine("Returned with " + sList.Count.ToString +  " elements")
    for each line as String in sList
        Console.WriteLine(line)
    next
End Sub

得到这个输出

Call listCleaning with 9 elements
09:01:01,003 --> 02:02:02 003
08:01:01,003 --> 02:02:02,003
07:01:01,003 --> 02:02:02,003
06:AA:01,003   --> 02:02:02,003
05:01:01,003 -->    02:02:02,003
04:01:01,003 --> 02:02:02,003
03:01:01,003 --> 02:02:02,003
sdsdfsdfsd03 --> 02:02:02,003
01:01:01,003 --> 02:02:02,003
Returned with 3 elements
sdsdfsdfsd03 --> 02:02:02,003
06:AA:01,003   --> 02:02:02,003
09:01:01,003 --> 02:02:02 003
于 2012-07-14T20:50:18.153 回答
0

回答第 2 点:

您不能在迭代期间修改集合。那么你

  1. 需要将要删除的项目存储在另一个集合中或
  2. 反向迭代(感谢@Oded)或
  3. 使用List.RemoveAll(看底部)或
  4. 使用 Linq:

    var dontRemove = From line In sList
        Where line <> "" AndAlso Not Integer.TryParse(line, Nothing) AndAlso Not reg.IsMatch(pattern)
    

现在您可以安全地从列表中删除这些行或创建一个新列表:

sList = dontRemove.ToList()

如果您正在使用List(Of T)最好的选择是使用List.RemoveAll并传递谓词应该删除哪些项目:

Dim regex = New Regex("\d{2}:\d{2}:\d{2},\d{3}\s+-->\s+\d{2}:\d{2}:\d{2},\d{3}", RegexOptions.Compiled)
sList.RemoveAll(Function(line) line.Length = 0 _
                    OrElse Integer.TryParse(line, Nothing) _
                    OrElse Not regex.IsMatch(line))

反向迭代列表的最佳方法是什么

For index As Int32 = sLines.Count - 1 To 0 Step -1
    Dim line = sLines(index)
Next`
于 2012-07-14T20:40:25.003 回答