🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
##### **条件表达式(?(Expression)yes|no)** 它是 **(?(<span style="color:red">?=</span>Expression)yes|no)** 的简写形式,相当于三元运算符 **(?=Expression)?yes:no** 如果“Expression”与可能出现的命名捕获组的组名相同,为避免混淆,可以采用“(?(?=Expression)yes|no)”方式显示声明“Expression”为子表达式,而不是捕获组名 | 表达式 | 条件特点 | 条件说明 | | --- | --- |--- | | **(?(1)yes\|no)** | 条件为数字 | 分组1如果有捕获,则进行 yes 部分匹配,否则 no 部分 | | **(?(?=a)yes\|no)** | 条件为预搜索 | 如果当前位置右侧是 a,则进行匹配 yes,否则匹配 no | | **(?(xxx)yes\|no)** | 不与分组命名吻合 | 如果不与任何分组命名吻合,则视为 **(?=xxx)** 相同 | | **(?(name)yes\|no)** | 与分组命名吻合 | 如果与某分组命名吻合,则视为判断该分组是否进行捕获 | | **(?(xxoo)yes)** | 只有一个条件表达式 | 当只有一个条件时那么yes只能在条件成立下匹配 | | **(?(xxoo)yes\|no1\|no2)** | 条件表达式大于2个 | 以第一个 **\|** 为准 成功匹配yes 不成功匹配no1\|no2 | `(?(?=a)\w{2}|\w)`    当前位置右侧如果是字符“a” ,则匹配两个“\w”,否则匹配一个“\w” ``` $str="a+(b*(c+d))/e+f-(g/(h-i))*j"; $pattern="/\(((?<Open>\()|(?<-Open>\))|[^()]+)*(?(Open)(?!))\)/"; ``` 看着难受 把他分开看容易些 ~~~ $pattern="/ \( #先匹配普通的开括号( ( (?<Open>\() #命名捕获组,遇到开括弧(则’Open’计数加1 | (?<-Open>\)) #狭义平衡组,遇到闭括弧)则’Open’计数减1 每匹配到一个“)”,就出栈最近入栈的Open捕获组,$matchs计数减1 | [^()]+ #非括弧的其它任意字符 )* (?(Open)(?!)) #判断是否还有’Open’,有则说明不配对,什么都不匹配 \) #匹配普通闭括号 /"; ~~~ 后面的(?(Open)(?!))用来保证堆栈中Open捕获组计数是否为0,也就是“(”和“)”是配对出现的 5. 最后的“)”,作为匹配的结束 需要对“(?!)”进行一下说明,它属于顺序否定环视,完整的语法是“(?!Expression)”。由于这里的“Expression”不存在,表示这里不是一个位置,所以试图尝试匹配总是失败的,作用就是在Open不配对出现时,报告匹配失败 平衡组用于匹配嵌套层次结构,常用于匹配HTML标签(当HTML内容不规范,起始标签和结束标签数量不同时,匹配出正确配对的标签),在此把表达式统一以`\w`为例。 * `(?'group'\w)` 捕获的分组(`\w`匹配到的内容)命名为`group`,并压入堆栈 * `(?'-group'\w)` 捕获分组(`\w`匹配到的内容)后,弹出`group`分组栈的栈顶内容(最后压入的捕获内容),堆栈本来为空,则本分组的匹配失败 * `(?(group)yes|no)` 如果`group`栈非空匹配表达式`yes`,否则匹配表达式`no` * `(?!)` 零宽负向先行断言,由于没有后缀表达式,试图匹配总是失败 ## 平衡组分狭义平衡组与广义平衡组 ### 狭义平衡组: **(?\<Close-Open\>Expression)** 一般都是省略的,写作“**(?\<-Open\>Expression)**” 狭义平衡组指.NET中定义的(?Expression) 广义平衡组并不是固定的语法规则,而是几种语法规则的综合运用,我们平时所说的平衡组通常指的是广义平衡组。本文中如无特殊说明,平衡组这种简写指的是广义平衡组 平衡组通常是由量词,分支结构,命名捕获组,狭义平衡组,条件判断结构组成的,量词和分支结构这里不做介绍,这里只对命名捕获组,狭义平衡组和条件判断结构做下说明 >[danger]注意:php不支持平衡组,我们可以通过递归达到同样的效果