Sub 递归()
'整体递归
' `(?0)` - 与`(?R)`相同,递归整个模式
reg.Pattern = "\(([^()]++|(?R))*\)"
Set mc = reg.Execute("(a(b(c)d)e)")
Debug.Print mc(0).Value
'数字捕获组递归
' `(?1)`, `(?2)`, `(?n)` - 递归引用第1、2、n个捕获组
' `(?+n)` - 相对递归,向后数第n个捕获组
' `(?-n)` - 相对递归,向前数第n个捕获组
reg.Pattern = "(\(([^()]++|(?1))*\))"
Set mc = reg.Execute("((()))")
Debug.Print mc(0).Value
'命名捕获组递归
' `(?&name)` - 递归名为name的捕获组(Perl语法)
' `(?P>name)` - Python风格语法
' `\g<name>` - Oniguruma风格语法
' `\g'name'` - Oniguruma单引号语法
reg.Pattern = "(?<p>\(([^()]++|(?&p))*\))"
Set mc = reg.Execute("(a(b)c)")
Debug.Print mc(0).Value
'带返回值的递归(PCRE2扩展,TODO:目前尚未支持)
' `(?R(grouplist))` - 递归整个模式并返回指定捕获组
' `(?n(grouplist))` - 递归第n个组并返回指定捕获组
' `(?&name(grouplist))` - 递归命名组并返回指定捕获组
'reg.Pattern = "(?(DEFINE)(?<wordpart>(\w+)))(?&wordpart([1]))"
'Set mc = reg.Execute("Sample text")
'Debug.Print mc(0).Value
'递归条件检测
' `(?(R)yes-pattern|no-pattern)` - 检查是否在递归中
' `(?(R1)yes-pattern|no-pattern)` - 检查是否在第1组的递归中
' `(?(R&name)yes-pattern|no-pattern)` - 检查是否在名为name的组的递归中
reg.Pattern = "<(\w+)(?>(?:""[^""]*""|'[^']*'|[^>])*?)>(?:(?R)|[^<]*)</\1>"
Set mc = reg.Execute("<div><span>text</span></div>")
Debug.Print mc(0).Value
'模拟平衡组,比较复杂似乎不如算法来得实在
'任意层关闭的圆括号
reg.Pattern = "\(([^()]++|(?R))*\)"
Set mc = reg.Execute("(1(2(3)(3(4(5(6)5)4)3)2)1)")
Debug.Print mc(0).Value
'更复杂的括号匹配,支持()[]{}
reg.Pattern = "(?<balanced>\(([^()]++|(?&balanced))*\)|{([^{}]++|(?&balanced))*}|[^\[\]{}()]*)"
Set mc = reg.Execute("(11(21[31](32(41(51(61)52)42)33)22)12)")
Debug.Print mc(0).Value
' (?R(grouplist)) recurse whole pattern, returning capture groups
' (PCRE2 extension)
' (?n(grouplist)) )
' (?+n(grouplist)) ) call subroutine, returning capture groups
' (?-n(grouplist)) ) (PCRE2 extension)
' (?&name(grouplist)) )
' (?P>name(grouplist)) )
'示例:嵌套引号匹配
'目标:匹配带有嵌套引号的字符串,如 "outer "inner" outer",并捕获每一层引号内的内容
'("(?R(1))")|([^"]+)
' 第一层:("(?R(1))"):匹配一个双引号,然后递归调用整个模式
' 递归调用:(?R(1)) 递归地匹配内部内容,并只返回捕获组 1 的内容(即内部引号)
' 基线情况:([^"]+):匹配不包含引号的普通文本
' 结果:每次递归只捕获当前层的引号内容,最终可以提取出所有嵌套层级的内容
reg.Pattern = "(""(?R(1))"")|([^""]+)"
Set mc = reg.Execute("""outer ""inner"" outer""")
Debug.Print mc.Count
'(?n(grouplist)) - 递归调用编号子例程并指定返回组
'作用:递归调用编号为 n 的 子例程(Subroutine)
'返回:仅返回 (grouplist) 中指定的捕获组
'示例:限定层级的 HTML 标签匹配
' 目标:匹配至多 3 层 嵌套的 <div> 标签,并捕获最内层的内容
' <(?<tag>div)>(?:(?R(1))|([^<]+))</\k<tag>>
' 解释:
' (?<tag>div):捕获标签名为 div
' (?R(1)):递归调用整个模式,但只返回捕获组 1(即最内层的内容)
' ([^<]+):基线情况,匹配不含 < 的普通文本
' 层级控制:通过外部逻辑或限定循环次数,确保递归深度不超过 3
'
'(?+n(grouplist)) - 正向调用子例程并指定返回组
'示例:正向引用的嵌套括号
'目标:匹配嵌套的圆括号 (),并捕获每一层的内容
'\((?:(?+1(1))|([^()]+))\)
' 解释:
' (?+1(1)):正向调用编号为 1 的子例程(即当前正则表达式本身),但只返回捕获组 1 的内容
' ([^()]+):基线情况,匹配不含括号的普通文本
' 结果:递归匹配至最内层括号,捕获每一层的内容
'(?-n(grouplist)) - 反向调用子例程并指定返回组
'示例:反向引用的 HTML 列表结构
'目标:匹配嵌套的 <ul> 列表结构,并捕获最内层的 <li> 内容
'<ul>(?:(?-1(1))|<li>[^<]+</li>)</ul>
' 解释:
' (?-1(1)):反向调用编号为 1 的子例程(即当前正则表达式本身),但只返回捕获组 1 的内容
' <li>[^<]+</li>:基线情况,匹配最内层的列表项
' 结果:递归匹配嵌套的列表结构,捕获每一层的列表项内容
'(?&name(grouplist)) - 调用命名子例程并指定返回组
'示例:调用自定义的引号匹配子例程
'目标:使用自定义子例程 quote 匹配单引号和双引号,并捕获内容
'(?<quote>"([^"]+)"|'([^']+)')
'(?"e(1,2))
' 解释:
' (?<quote>"([^"]+)"|'([^']+)'):定义了一个名为 quote 的子例程,匹配双引号或单引号内的内容
' (?"e(1,2)):调用 quote 子例程,并返回捕获组 1(双引号内容)和捕获组 2(单引号内容)
' 结果:根据输入字符串的引号类型,捕获对应的内容
End SubCopyright © 2025- vba.vip All Rights Reserved.