递归表达式

当前位置:首页>正则>递归表达式

递归表达式

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>"([^"]+)"|'([^']+)')
'(?&quote(1,2))
'  解释:
'  (?<quote>"([^"]+)"|'([^']+)'):定义了一个名为 quote 的子例程,匹配双引号或单引号内的内容
'  (?&quote(1,2)):调用 quote 子例程,并返回捕获组 1(双引号内容)和捕获组 2(单引号内容)
'  结果:根据输入字符串的引号类型,捕获对应的内容
End Sub