2025年02月10日
分组
分组在正则中用()表示,根据小菜理解,分组的作用有两个:1.将某些规律看成是一组,然后进行组级别的重复,可以得到意想不到的效果。2.分组之后,可以通过后向引用简化表达式(\1 或者$1)。分组举列先来看第一个作用,对于IP地址的匹配,简单的可以写为如下形式:
\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3}但仔细观察,我们可以发现一定的规律,可以把.\d{1,3}看成一个整体,也就是把他们看成一组,再把这个组重复3次即可。表达式如下:
\d{1,3}(.\d{1,3}){3} 再来看第二个作用,就拿匹配
<(title)>.*\1>对于分组而言,整个表达式永远算作第0组,在本例中,第0组是<(title)>.*\1>,然后从左到右,依次为分组编号,因此,(title)是第1组。注意:用\1这种语法,可以引用某组的文本内容,但不能引用正则表达式。例如刚刚的IP地址正则表达式为\d{1,3}(.\d{1,3}){3},里边的\d{1,3}重复了两次,如果利用后向引用简化,表达式如下:
(\d{1,3})(.\1){3}经过实际测试,会发现这样写是错误的,为什么呢?后向引用,引用的仅仅是文本内容,而不是正则表达式!也就是说,组中的内容一旦匹配成功,后向引用,引用的就是匹配成功后的内容,引用的是结果,而不是表达式。因此,(\d{1,3})(.\1){3}这个表达式实际上匹配的是四个数都相同的IP地址,比如:123.123.123.123。 不捕获不捕获就是在分组的前边加上?:,可以在不需要捕获分组的表达式中使用,加快表达式执行速度。就拿匹配
<(title)>.*\1>但是如果是(?:title),则\1就不能捕获到这个子组了,只能捕获第一个出现的非?:的分组作为\1同时注意(?:title)本身会在完整匹配中,只是不在子组中,注意和断言的区别
$str="ab123ff";//正常,完整匹配为ab123ff, 有两个子组ab, ffpreg_match_all("|([a-z]{2}).*([a-z]{2})|U", $str, $out);echo"
";print_r($out);echo"";//不捕获分组,完整匹配为ab23ff, 有一个子组ffpreg_match_all("|(?:[a-z]{2}).*([a-z]{2})|U", $str, $out);echo"
";print_r($out);echo"";//断言,完整匹配为123ff, 有一个子组ffpreg_match_all("|(?<=[a-z]{2}).*([a-z]{2})|U", $str, $out);echo"
";print_r($out);echo"";
断言所谓断言,就是指明某个字符串前边或者后边,将会出现满足某种规律的字符串。就拿匹配
(?=X )零宽度正先行断言。仅当子表达式 X 在 此位置的右侧匹配时才继续匹配。例如,\w+(?=\d) 与后跟数字的单词匹配,而不与该数字匹配。此构造不会回溯。(?!X)零宽度负先行断言。仅当子表达式 X 不在 此位置的右侧匹配时才继续匹配。例如,例如,\w+(?!\d) 与后不跟数字的单词匹配,而不与该数字匹配 。(?<=X)零宽度正后发断言。仅当子表达式 X 在 此位置的左侧匹配时才继续匹配。例如,(?<=19)99 与跟在 19 后面的 99 的实例匹配。此构造不会回溯。(?