正则表达式:捕获捕获组中的组

时间:2015-05-13 14:50:51

标签: regex substring match capture-group

简介

(你可以跳到如果......如果你厌倦了介绍会怎么样?

这个问题并不是针对VBScript的(我只是在这种情况下使用它):我想找到一般正则表达式用法的解决方案(包括编辑器)。

这是在我想要创建Example 4 where 3 capture groups are used to split data across 3 cells in MS Excel的改编时开始的。 我需要捕获一个完整的模式,然后在其中捕获3个其他模式。然而,在同一个表达式中,我还需要捕获另一种模式并再次捕获其中的3种其他模式(是的,我知道......但在指向nutjob手指之前,请完成阅读)。

我首先考虑Named Capturing Groups然后我意识到我不应该«混合命名和编号的捕获组»因为它不推荐使用«因为风味不一致组编号为

然后我调查了VBScript SubMatches«non-capturing» groups,我得到了针对特定案例的有效解决方案:

For Each C In Myrange
    strPattern = "(?:^([0-9]+);([0-9]+);([0-9]+)$|^.*:([0-9]+)\s.*:([0-9]+).*:([a-zA-Z0-9]+)$)"

    If strPattern <> "" Then
        strInput = C.Value

        With regEx
            .Global = True
            .MultiLine = True
            .IgnoreCase = False
            .Pattern = strPattern
        End With

        Set rgxMatches = regEx.Execute(strInput)

        For Each mtx In rgxMatches
            If mtx.SubMatches(0) <> "" Then
                C.Offset(0, 1) = mtx.SubMatches(0)
                C.Offset(0, 2) = mtx.SubMatches(1)
                C.Offset(0, 3) = mtx.SubMatches(2)
            ElseIf mtx.SubMatches(3) <> "" Then
                C.Offset(0, 1) = mtx.SubMatches(3)
                C.Offset(0, 2) = mtx.SubMatches(4)
                C.Offset(0, 3) = mtx.SubMatches(5)
            Else
                C.Offset(0, 1) = "(Not matched)"
            End If
        Next
    End If
Next

Here's a demo in Rubular of the regex。 在这些:

  

124; 12; 3
  我的id1:213我的id2:232我的话:ins4yanrgx
  :8587459:18254182540215:dcpt
  0; 1; 2

它返回带有数字的前2个单元格和带有数字或单词的3 rd 。 基本上我使用了具有2个“父”模式的非捕获组(“父母”=我要检测其他子模式的宽模式)。如果1 st 父模式具有匹配的子模式(1 st 捕获组),那么我将其值和此模式的其余捕获组放在3个单元格中。如果没有,我检查4 th 捕获组(属于2 nd 父模式)是否匹配,并将剩余的子模式放在相同的3个单元格中。 / p>

如果......

而不是像这样:

(?:^(\d+);(\d+);(\d+)$|^.*:(\d+)\s.*:(\d+).*:(\w+)$|what(ever))

这样的事情是可能的:

(#:^(\d+);(\d+);(\d+)$)|(#:^.*:(\d+)\s.*:(\d+).*:(\w+)$)|(#:what(ever))

(#:而不是创建非捕获组的情况下,将创建一个“父”编号的捕获组。 通过这种方式,我可以做类似Example 4的事情:

C.Offset(0, 1) = regEx.Replace(strInput, "#$1")
C.Offset(0, 2) = regEx.Replace(strInput, "#$2")
C.Offset(0, 3) = regEx.Replace(strInput, "#$3")

它将搜索父模式,直到它在子模式中找到匹配(第一个匹配将被返回,理想情况下,不会搜索剩余的匹配)。

有没有这样的东西?或者我是否完全遗漏了正则表达式允许这样做的事情?

其他可能的变化:

  • 直接引用父母和子女模式,例如:#2$3(在我的示例中,这相当于$6);
  • 在其他人中创建尽可能多的捕获组(我想它会更复杂但也是最有趣的部分),例如:使用正则表达式(相同的语法),如(#:^_(?:(#:(\d+):\w+-(\d))|(#:\w+:(\d+)-(\d+)))_$)|(#:^\w+:\s+(#:(\w+);\d-(\d+))$)和获取{{1}在以下模式中:
      

    ##$1它会匹配: 123
      _123:smt-4_它会匹配: 432
      _ott:432-10_它会匹配:特殊

请告诉我,如果您发现此逻辑中存在任何错误或缺陷,我会尽快编辑。

1 个答案:

答案 0 :(得分:4)

这通常是捕获大部分相同数据的情况 唯一的区别在于形式。

有一个名为Branch Reset的正则表达式构造 它在大多数Perl兼容引擎上提供。不是Java也不是Dot Net 它主要是保存正则表达式资源,并使处理匹配更容易。

你提到的替代方案无论如何都没有用,它实际上只是使用了 更多资源。你仍然需要看看匹配的东西,看看你在哪里 但是你只需要检查一个集群中的一个组来判断哪个组 组有效(&lt; - 如果使用分支重置,这是不必要的)。

下面是使用 RegexFormat 6构建的)

这是分支重置版本:

 # (?|^(\d+);(\d+);(\d+)$|^.*:(\d+)\s.*:(\d+).*:(\w+)$|what(ever)()())

 (?|
      ^ 
      ( \d+ )                       # (1)
      ;
      ( \d+ )                       # (2)
      ;
      ( \d+ )                       # (3)
      $ 
   |  
      ^ .* :
      ( \d+ )                       # (1)
      \s .* :
      ( \d+ )                       # (2)
      .* :
      ( \w+ )                       # (3)
      $ 
   |  
      what
      ( ever )                      # (1)
      ( )                           # (2)
      ( )                           # (3)
 )

这是你的两个正则表达式。请注意,“父”捕获实际上会增加组的数量(这会降低引擎的速度):

 # (?:^(\d+);(\d+);(\d+)$|^.*:(\d+)\s.*:(\d+).*:(\w+)$|what(ever))

 (?:
      ^ 
      ( \d+ )                       # (1)
      ;
      ( \d+ )                       # (2)
      ;
      ( \d+ )                       # (3)
      $ 
   |  
      ^ .* :
      ( \d+ )                       # (4)
      \s .* :
      ( \d+ )                       # (5)
      .* :
      ( \w+ )                       # (6)
      $ 
   |  
      what
      ( ever )                      # (7)
 )

    # (#:^(\d+);(\d+);(\d+)$)|(#:^.*:(\d+)\s.*:(\d+).*:(\w+)$)|(#:what(ever))

    (                             # (1 start)
         \#: ^ 
         ( \d+ )                       # (2)
         ;
         ( \d+ )                       # (3)
         ;
         ( \d+ )                       # (4)
         $ 
    )                             # (1 end)
 |  
    (                             # (5 start)
         \#: ^ .* :
         ( \d+ )                       # (6)
         \s .* :
         ( \d+ )                       # (7)
         .* :
         ( \w+ )                       # (8)
         $ 
    )                             # (5 end)
 |  
    (                             # (9 start)
         \#:what
         ( ever )                      # (10)
    )                             # (9 end)