条件子组
条件子组语法
条件子组
,(?(if)then_pattern|else_pattern)
或者(?(if)then_pattern)
,允许我们创建带有条件的正则表达式。如果(if)
为true,正则引擎就会去匹配then_pattern
。否则,如果存在else_pattern
,就会去匹配else_pattern
。 而对于if
可以是一个断言(?(?=regex)then_pattern|else_pattern)
,也可以是一个数字(?(1)then_pattern|else_pattern)
。
条件如果是一个断言,这个很好理解,因为断言本身就是一个判断。如果条件是一个数字,就是表示这个数字对应的捕获子组匹配成功的话,条件true,如果匹配失败,则条件false。
示例
下面我们看一个例子/(a)?b(?(1)c|d)/
,这个正则可以匹配字符串"abc"
、"bd"
,也可以匹配字符串"abd"
中的"bd"
;但是不能匹配"bc"
。
首先我们看匹配"abc"
。正则(a)
可以匹配第一个字符'a'
;然后是正则b
匹配下一个字符'b'
;接下来进入条件表达式,因为是一个数字1,第一个子组a
匹配成功,这里的条件为真,所以正则引擎匹配then_pattern
c
和下一个字符c
。可以匹配成功,到此整个正则表达式匹配成功。
下面我们看匹配字符串"bd"
。正则(a)
匹配第一个字符'b'
失败,但是后面跟着的是?
,允许(a)
匹配失败,所以继续下一个正则b
,匹配第一个字符'b'
成功。下面进入正则的条件(1)
,因为前面没有子组捕获成功,所以此时条件为false。正则引擎走else_pattern,使用d
匹配下一个字符'd'
,成功。至此整个正则表达式匹配成功。
对于为什么不能匹配"bc"
。各位可以按照上面的遍历过程自行分析。
最有意思的应该是为什么能匹配字符串"abd"
中的"bd"
。注意,这里只是匹配其中的"bd"
,而不是匹配成功正字字符串"abd"
。有匹配到内容,说明正则表达式最后是成功的。但是按照我们上面的说法,即然(a)
匹配成功了,那(1)
为真,应该走then_pattern,c
不能和字符'd'
匹配,所以应该是匹配失败的。说的没错,到这个地方逻辑都是没问题的。但是需要注意的是,else_pattern在此时还没有被尝试,虽然前面子组捕获成功,条件为 true。但是此时也只是then_pattern c
被尝试了,它虽然失败了,整个正则表达式却还没有完成。所以正则引擎会从头开始匹配正则表达式,对于目标字符串则会前进一个字符,也就是从字符'b'
开始。再次从(a)
开始匹配,此时匹配失败。引擎继续一下个正则b
和字符'b'
匹配成功。因为前面子组捕获失败,所以条件为false,此时走else_pattern,正则d
和下一个字符d
匹配成功。整个正则此时已经走完,最后匹配成功"bd"
。 通过这个例子我们可以看到,其实条件子组和我们正常的编程语言的 if(){}else{}
还是有区别的。在条件子组中,then_pattern和 else_pattern 更像是可选路径,类似于(then_pattern|else_pattern)
。在整个正则表达式中,所有的正则其实都是条件,就类似于我们编程语言中的if(){}else{}
中if后面的()
里的条件,而不是{}
里的实体。所以对于整个条件子组(?(if)then_pattern|else_pattern)
可以理解成 (if) && then_pattern | else_pattern
。如果(if)为true,则还要去判断then_pattern,如果它也为true,那|
前面部分就为true了,对于|
后面的条件也就不用再判断了,因为或
条件是只要有一个为true,整个表达式就为true。而如果(if)
和 then_pattern其中有一个为false,那前面部分就是false了。对于|
后面的就会去进行判断,当else_pattern为true,整个条件表达式同样也为true。而向我们上面匹配"abd"
这个例子就是 (if)
为true,但是then_pattern为false的情况,所以else_pattern 还是会去进行判断。只是正则引擎的判断方式不一样,需要对整个正则进行回溯。但是道理是一样的。
对于(if)
是断言的情况,我们自己也可以举些例子按照上面的方法进行分析。
还有个问题需要说明一下,对于条件子组,只能有两个可选项——then_pattern
和else_pattern
。如果超过了两个,会产生编译错误。当然了,对于then_pattern和else_pattern本身可以是有多个可选项的。也就是说then_pattern和else_pattern必须是原子的。例如:(?(if)(then1|then2|then3)|(else1|else2|else3))
这是可以的。但是如果是(?(if)then1|then2|then3|else1|else2)
这样的,在编译的时候就会报错了。