【问题标题】:Complex Regex Matching with Capture Groups与捕获组的复杂正则表达式匹配
【发布时间】:2014-01-30 05:33:14
【问题描述】:

我正在尝试匹配天气报告中的某些天气(METAR 格式,如果有帮助的话)。要匹配的文本可以包含以下内容:

“RA”或“SN”或“TS”后跟“B”和两位或四位数字,或“E”和两位或四位数字,或两者,或多个“B”和“E”组(例如B05E20B45),导致类似“RAB05E20B45”的东西。这意味着“雨从 05 时开始,在 20 时结束,并在 45 时再次开始”。此外,在同一个字符串中可以有多个这样的结构(例如,“RAB05E20SNB25E55”=“雨从 05 开始,在 20 结束,然后下雪从 25 开始,在 55 结束”)。

以下是一些示例输入和我想获得的输出:

RAB05                     RAB05
RAB05E15                  RAB05E15
RAB05E15SNB25             RAB05E15     SNB05
RAB05E15SNB25E55          RAB05E15     SNB25E55
TSE01RAB05E15SNB25        TSE01        RAB05E15     SNB25
TSB01E55RAE15SNB25E55     TSB01E55     RAE15        SNB25E55

我很自大地认为下面会做到这一点......

((?:RA|SN|TS)(?:(?:B|E)(?:\d{2}|\d{4}))+)+

...但既然我在这里为此哭泣,显然没有。

这是我的测试代码(VB 2013):

Imports System.Text.RegularExpressions

Public Class Form1
    Dim sItem As String = "TSB05E10RAB15"
    Dim sPattern As String = "((?:RA|SN|TS)(?:(?:B|E)(?:\d{2}|\d{4}))+)+"

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        If Regex.Match(sItem, sPattern).Success Then
            Dim rxMatches As GroupCollection = Regex.Match(sItem, sPattern, RegexOptions.IgnoreCase).Groups

            '0th item is the entire match (e.g. TSB05E10RAB15)
            'Succeeding elements are capture groups
            For i = 1 To rxMatches.Count - 1
                MessageBox.Show("Match #" & i & " = " & rxMatches(i).Value)
            Next
        End If
    End Sub
End Class

我期望的结果是“TSB05E10”和“RAB15”,但我得到的只是“RAB15”。

我搜索了以下内容,但无济于事:

如果有人愿意向我展示我的方式的错误......

编辑:

感谢所有提供帮助的人。这是可行的解决方案:

Imports System.Text.RegularExpressions

Public Class Form1
    Dim sItem As String = "TSB05E10SHRAB10E15SNB25E35B45E55"
    Dim sPattern As String = "(?:(?:SH)?(?:RA|SN)|TS)(?:(?:B|E)(?:\d{2}|\d{4}))+"
    Dim rx As New Regex(sPattern, RegexOptions.IgnoreCase)

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim matches As MatchCollection = rx.Matches(sItem)

        Label1.Text = "Input: " & sItem

        For Each match As Match In matches
            Dim groups As GroupCollection = match.Groups

            ListBox1.Items.Add(groups.Item(0).Value)
        Next
    End Sub
End Class

【问题讨论】:

  • 你的正则表达式matches all your examples。有什么问题?
  • 我也觉得不错。 See it working here 我检查了全局复选框并使用了以下内容:((RA|SN|TS)((B|E)\d{2,4})+)
  • 正如他们所说的那样,它可以工作,你能提供一个它应该工作但它不工作的样本吗?!
  • 我相信第一列是数据,其余列是使用正则表达式解析出来的部分。
  • 有没有理由用空格分割它然后解析单个元素不起作用?我想这会让你的代码更干净(更容易理解和维护)。正则表达式很酷,但有时它们会让人头疼,最好避免使用。

标签: regex vb.net


【解决方案1】:

那些是真正的 METAR 吗?我原以为您需要为每种降水类型设置开始时间和结束时间。此外,如果降水是阵雨,则可能在降水类型之前有一个 SH。此外,您将数字量词指定为 {2,4},表示 2、3 或 4;正如你所说,它确实应该是 2 或 4。

无论如何,根据您的要求(并添加可选的 SH 并使用非捕获组来减少开销)尝试:

(?:SH)?(?:RA|SN|TS)(?:(?:B|E)(?:\d{2}|\d{4}))+

编辑: 缩短正则表达式。

关于您的正则表达式,您的问题是锚点,以及当您想分别解析不同的降水类型时重复降水类型的事实

编辑:我不确定 VB 2013,但在其他 VB 变体中,您需要将 Regex 对象的 Global 属性设置为 True。


正则表达式的解释:

  • (?:SH)? - 可选的非捕获组匹配“SH”
  • (?:RA|SN|TS) - 匹配“RA”或“SN”或“TS”的非捕获组
  • (?:(?:B|E)(?:\d{2}|\d{4}))+ - “B”或“E”后跟 2 或 4 位数字(可以重复一次或多次)

非捕获组仅表示括号中的内容用作匹配的一部分,但该组未“保存”以供以后访问(这是常规括号的工作方式)。

如果你把它全部分解,如果你花时间理解它真的很简单。

【讨论】:

  • 这个正则表达式让我想起了为什么我通常不将它们作为我的第一个解决方案......我确信它是正确的(可能),但阅读它就像阅读汇编一样。
  • 我以前在汇编中编程。也许这就是为什么我发现正则表达式最困难的部分是理解问题:-)
  • 它是“真实的”样本数据,因为它是有效的,但不,我没有从真实的 METAR 中复制它。不必同时有开始时间和结束时间(如果它正在进行中,或者在之前的观察中开始)。是的,你对阵雨的看法是对的,但我暂时不考虑这一点,以便在不增加复杂性的情况下让基础知识发挥作用。
  • @Brian 我的正则表达式是否按照您的要求工作?我的假设是否正确,即第 1 列是您的数据,而其他列是需要返回的数据?
  • @Brian 我刚刚更新了我的答案,表明您可能需要将 Global 属性设置为 True。然后每个都将作为单独的匹配返回。无需捕获组和子匹配。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多