正则表达式:捕获组内的捕获组
Regex: capturing groups within capture groups
简介
(你可以跳到 如果... 如果你对介绍感到厌倦了怎么办)
这个问题不是专门针对VBScript的(我只是在这种情况下使用它):我想找到一个通用正则表达式用法的解决方案(包括编辑器)。
这是我想改编 Example 4 where 3 capture groups are used to split data across 3 cells in MS Excel 的时候开始的。
我需要捕获一个完整的模式,然后在其中捕获 3 个其他模式。然而,在同一个表达式中,我还需要捕获另一种模式并再次捕获其中的其他 3 个模式(是的,我知道......但在指指点点之前,请完成阅读)。
我首先想到 Named Capturing Groups 然后我意识到我不应该 «混合命名和编号捕获组» 因为它 « 不推荐因为口味在组的编号方式上不一致».
然后我调查了 VBScript SubMatches and «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
my id1:213 my id2:232 my word:ins4yanrgx
:8587459 :18254182540215 :dcpt
0;1;2
它 returns 前 2 个单元格带有数字,第 3rd 带有数字或单词。
基本上我使用了一个具有 2 "parent" 模式的非捕获组("parents" = 我想检测其他子模式的广泛模式)。如果 1st 父模式有一个匹配的子模式(1st 捕获组),那么我将其值和剩余的捕获组放在一起3 个单元格中的模式。如果没有,我检查 4th 捕获组(属于 2nd 父模式)是否匹配并将剩余的子模式放在相同的 3 个单元格。
如果……怎么办
而不是像这样:
(?:^(\d+);(\d+);(\d+)$|^.*:(\d+)\s.*:(\d+).*:(\w+)$|what(ever))
这样的事情是可能的:
(#:^(\d+);(\d+);(\d+)$)|(#:^.*:(\d+)\s.*:(\d+).*:(\w+)$)|(#:what(ever))
其中 (#:
不是创建 非捕获 组,而是创建 "parent" 编号捕获组。
通过这种方式,我可以做类似于 Example 4:
的事情
C.Offset(0, 1) = regEx.Replace(strInput, "#")
C.Offset(0, 2) = regEx.Replace(strInput, "#")
C.Offset(0, 3) = regEx.Replace(strInput, "#")
它将搜索父模式,直到在子模式中找到匹配项(将返回第一个匹配项,理想情况下,不会搜索其余的)。
已经有这样的东西了吗? 或者我是否完全遗漏了正则表达式中允许这样做的东西?
其他可能的变化:
- 直接引用父子模式,例如:
#2
(在我的示例中这相当于 </code>);</li>
<li>在其他人中根据需要创建尽可能多的捕获组(我想这会更复杂但也是最有趣的部分),例如:使用正则表达式(相同的语法)如 <code>(#:^_(?:(#:(\d+):\w+-(\d))|(#:\w+:(\d+)-(\d+)))_$)|(#:^\w+:\s+(#:(\w+);\d-(\d+))$)
和获取 ##
的模式如下:
_123:smt-4_
it would match in: 123
_ott:432-10_
it would match in: 432
yant: special;3-45235
it would match in: special
如果您发现此逻辑中有任何错误或缺陷,请告诉我,我会尽快进行编辑。
这通常是要捕获大部分相同数据的情况。
唯一的区别在于形式。
有一个称为 Branch Reset 的正则表达式结构。
它在大多数 Perl 兼容引擎上提供。不是 Java 也不是 Dot Net。
它主要只是节省正则表达式资源并使处理匹配更容易。
你提到的替代方案没有任何帮助,它实际上只是使用
更多资源。您仍然需要查看匹配的内容才能查看您的位置。
但是你只需要检查一个集群中的一个组来告诉其他哪个
组是有效的(<- 如果使用分支重置,这是不必要的)。
(下面的是使用 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)
)
这是你的两个正则表达式。请注意 'parent' 捕获实际上增加了组的数量(这会减慢引擎速度):
# (?:^(\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)
简介
(你可以跳到 如果... 如果你对介绍感到厌倦了怎么办)
这个问题不是专门针对VBScript的(我只是在这种情况下使用它):我想找到一个通用正则表达式用法的解决方案(包括编辑器)。
这是我想改编 Example 4 where 3 capture groups are used to split data across 3 cells in MS Excel 的时候开始的。 我需要捕获一个完整的模式,然后在其中捕获 3 个其他模式。然而,在同一个表达式中,我还需要捕获另一种模式并再次捕获其中的其他 3 个模式(是的,我知道......但在指指点点之前,请完成阅读)。
我首先想到 Named Capturing Groups 然后我意识到我不应该 «混合命名和编号捕获组» 因为它 « 不推荐因为口味在组的编号方式上不一致».
然后我调查了 VBScript SubMatches and «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
my id1:213 my id2:232 my word:ins4yanrgx
:8587459 :18254182540215 :dcpt
0;1;2
它 returns 前 2 个单元格带有数字,第 3rd 带有数字或单词。 基本上我使用了一个具有 2 "parent" 模式的非捕获组("parents" = 我想检测其他子模式的广泛模式)。如果 1st 父模式有一个匹配的子模式(1st 捕获组),那么我将其值和剩余的捕获组放在一起3 个单元格中的模式。如果没有,我检查 4th 捕获组(属于 2nd 父模式)是否匹配并将剩余的子模式放在相同的 3 个单元格。
如果……怎么办
而不是像这样:
(?:^(\d+);(\d+);(\d+)$|^.*:(\d+)\s.*:(\d+).*:(\w+)$|what(ever))
这样的事情是可能的:
(#:^(\d+);(\d+);(\d+)$)|(#:^.*:(\d+)\s.*:(\d+).*:(\w+)$)|(#:what(ever))
其中 (#:
不是创建 非捕获 组,而是创建 "parent" 编号捕获组。
通过这种方式,我可以做类似于 Example 4:
C.Offset(0, 1) = regEx.Replace(strInput, "#")
C.Offset(0, 2) = regEx.Replace(strInput, "#")
C.Offset(0, 3) = regEx.Replace(strInput, "#")
它将搜索父模式,直到在子模式中找到匹配项(将返回第一个匹配项,理想情况下,不会搜索其余的)。
已经有这样的东西了吗? 或者我是否完全遗漏了正则表达式中允许这样做的东西?
其他可能的变化:
- 直接引用父子模式,例如:
#2
(在我的示例中这相当于</code>);</li> <li>在其他人中根据需要创建尽可能多的捕获组(我想这会更复杂但也是最有趣的部分),例如:使用正则表达式(相同的语法)如 <code>(#:^_(?:(#:(\d+):\w+-(\d))|(#:\w+:(\d+)-(\d+)))_$)|(#:^\w+:\s+(#:(\w+);\d-(\d+))$)
和获取##
的模式如下:_123:smt-4_
it would match in: 123
_ott:432-10_
it would match in: 432
yant: special;3-45235
it would match in: special
如果您发现此逻辑中有任何错误或缺陷,请告诉我,我会尽快进行编辑。
这通常是要捕获大部分相同数据的情况。
唯一的区别在于形式。
有一个称为 Branch Reset 的正则表达式结构。
它在大多数 Perl 兼容引擎上提供。不是 Java 也不是 Dot Net。
它主要只是节省正则表达式资源并使处理匹配更容易。
你提到的替代方案没有任何帮助,它实际上只是使用
更多资源。您仍然需要查看匹配的内容才能查看您的位置。
但是你只需要检查一个集群中的一个组来告诉其他哪个
组是有效的(<- 如果使用分支重置,这是不必要的)。
(下面的是使用 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)
)
这是你的两个正则表达式。请注意 'parent' 捕获实际上增加了组的数量(这会减慢引擎速度):
# (?:^(\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)