比如'#[[:upper:]]#'匹配大写字母 '#[[:alpha:]]#' 匹配字母 可选路径| 竖线字符用于分离模式中的可选路径。 比如模式gilbert|Sullivan匹配 ”gilbert” 或者 ”sullivan”。 竖线可以在模式中出现任意多个,并且允许有空的可选路径(匹配空字符串)。 匹配的处理从左到右尝试每一个可选路径,并且使用第一个成功匹配的。 如果可选路径在子组(下面定义)中, 则”成功匹配”表示同时匹配了子模式中的分支以及主模式中的其他部分。 代码5 $p='#p(hp|ython|erl)#';$str="php python perl";preg_match_all($p,$str,$all);print_r($all); 子组(子模式) 子组通过圆括号分割界定,并且它们可以嵌套,主要有以下两种用法与功能 1.将可选分支局部化。比如 模式 p(hp|ython|erl) 匹配php,python,perl中的一个 2.将子组设定为捕获子组。 整个模式匹配后, 左括号从左至右出现的次序就是对应子组的下标(从 1 开始), 可以通过这些下标数字来获取捕获子模式匹配结果。 代码6 $p='#(\d)#';$str="abc123";$r=preg_replace($p,'<font color=red>\1</font>',$str);echo $r; 但当只想分组而又不想捕获时 在子组定义的左括号后面紧跟字符串 ”?:” 会使得该子组不被单独捕获, 并且不会对其后子组序号的计算产生影响 代码7:匹配数字 把数字改为红色的 $p='#.*(?:\d).*([a-z])#U';$str="3df5g";$r=preg_replace($p,'<font color=red>\1</font>',$str);echo $r; 如果匹配数字的模式不加?: 那么\1代表的就是匹配就是数字,加上后只是分组不捕获了,\1就代表捕获的字母了 为了方便简写,如果需要在非捕获子组开始位置设置选项, 选项字母可以位于 ? 和 : 之间,比如: (?i:saturday|Sunday) (?:(?i)saturday|Sunday) 其中i是模式修正符,忽略大小写 上面两种写法实际上是相同的模式。因为可选分支会从左到右尝试每个分支, 并且选项没有在子模式结束前被重置, 并且由于选项的设置会穿透对后面的其他分支产生影响,因此, 上面的模式都会匹配 ”SUNDAY” 以及 ”Saturday”。 在 PHP 4.3.3 中,可以对子组使用 (?P8a11bc632ea32a57b3e3693c7987c420pattern) 的语法进行命名。 这个子模式将会在匹配结果中同时以其名称和顺序(数字下标)出现, PHP 5.2.2中又增加了两种味子组命名的语法: (?8a11bc632ea32a57b3e3693c7987c420pattern) 和 (?’name’pattern)。 代码如下8: $p="#.*(?<alpha>[a-z]{3})(?'digit'\d{3}).*#";$str="abc123111def111g";preg_match_all($p,$str,$arr);print_r($arr); 结果: 有时需要多个匹配可以在一个正则表达式中选用子组。 为了让多个子组可以共用一个后向引用数字的问题, (?\语法允许复制数字。 考虑下面的正则表达式匹配Sunday: (?:(Sat)ur|(Sun))day 这里当后向引用 1 空时Sun 存储在后向引用 2 中. 当后向引用 2 不存在的时候 Sat 存储在后向引用 1中。 使用 (?|修改模式来修复这个问题: 代码9: $p='#(?:(sat)ur|(sun))day#';$str="sunday saturday";preg_match_all($p,$str,$arr);print_r($arr); 结果: (?|(Sat)ur|(Sun))day 使用这个模式, Sun和Sat都会被存储到后向引用1中。 在看这个模式前先看以2个下代码 代码10-1 $p='#(a|b)\d#';$str="b2a1";preg_match_all($p,$str,$arr);print_r($arr); 结果是:Array ( [0] => Array ( [0] => b2 [1] => a1 ) [1] => Array ( [0] => b [1] => a ))代码10-2 $p='#((a)|b)\d#';$str="b2a1";preg_match_all($p,$str,$arr);print_r($arr); 结果: Array( [0] => Array ( [0] => b2 [1] => a1 ) [1] => Array ( [0] => b [1] => a ) [2] => Array ( [0] => [1] => a ))对10-2代码:第一次完整匹配到的内容是b2,所以包括匹配内容b的括号即为其第一个子模式是即为b,第二个子模式由于(a)没有匹配,所以为空第二次完整匹配到a1,其第一个子模式为a,第二次的由于((a)|b)是外层大括号里包含的代码10-3: $p='#((a)|(b))\d#';$str="b2a1";preg_match_all($p,$str,$arr);print_r($arr); 结果: Array( [0] => Array ( [0] => b2 [1] => a1 ) [1] => Array ( [0] => b [1] => a ) [2] => Array ( [0] => [1] => a ) [3] => Array ( [0] => b [1] => )) 代码10-4: $p='#(?:(a)|(b))\d#';$str="b2a1";preg_match_all($p,$str,$arr);print_r($arr); 结果:Array( [0] => Array ( [0] => b2 [1] => a1 ) [1] => Array ( [0] => [1] => a ) [2] => Array ( [0] => b [1] => )) 代码10: $p='#(?|(sat)ur|(sun))day#';$str="sunday saturday";preg_match_all($p,$str,$arr);print_r($arr); 结果 后向引用 如果紧跟反斜线的数字小于 10, 它总是一个后向引用。模式中的捕获数要大于等于后向引用的个数 后向引用会直接匹配被引用捕获组在目标字符串中实际捕获到的内容, 而不是匹配子组模式的内容 (sens|respons)e and \1ibility将会匹配 ”sense and sensibility” 和 ”response and responsibility”, 而不会匹配 ”sense and responsibility”。 代码11 $p='#(sens|respons)e and \1ibility#';$str="sense and sensibility response and responsibility sense and responsibility";preg_match_all($p,$str,$arr);print_r($arr); 结果 ab(?i)c匹配abC和abc (?i)+原子 表示(?i)后的原子不区分大小写 如果在后向引用时被强制进行了大小写敏感匹配 ((?i)abc)\s+\1 匹配 abc abc ABC ABC AbC AbC 只要两个一样不分大小写 但不匹配 ABC aBC等 这里其实要考虑的是后向引用期望得到的内容是和那个被引用的捕获子组得到的内容是完全一致的 代码12: $p='#((?i)abc)\s+\1#';$str="abc abc |ABC ABC |AbC AbC |abc Abc ";preg_match_all($p,$str,$arr);print_r($arr); 结果 可能会有超过一个的后向引用引用相同的子组。 一个子组可能并不会真正的用于特定的匹配,此时, 任何对这个子组的后向引用也都会失败。 先看以下代码13 $p='#(a|(bc))#';$str="abc ";preg_match_all($p,$str,$arr);print_r($arr); 完整匹配了2次 [0][0]是第一次完整的匹配 [1][0]是第一次匹配的第一个子模式 [2][0]是第一次匹配的第二个子模式 [0][1]第二次完整匹配 [1][1]第二次匹配的第一个子模式 [2][1]是第二次匹配的第二个子模式 从上面可以发现对于模式 (a|(bc)) 最外面的括号是第一个匹配子模式 里面的括号里的是第二个子模式 所以对于以下代码14: $p='#(a|(bc))\2#';$str="aabcbc";preg_match_all($p,$str,$arr);print_r($arr); 结果 当第一匹配a时,就没有第二子模式了 就无从\2谈起 所以第一次完整匹配中必须得有让第二个子模式存在的机会即里面的括号里的内容必须被匹配到,所以必须得有bc才能有匹配。 因为可能会有多达 99 个后向引用, 所有紧跟反斜线后的数字都可能是一个潜在的后向引用计数。 如果模式在后向引用之后紧接着还是一个数值字符, 那么必须使用一些分隔符用于终结后向引用语法。 以下代码15为例: $p='#([a-z]{3})\1 5#x';$str="aaaaaa5";preg_match_all($p,$str,$arr);print_r($arr); 模式后向引用\1后紧跟数字的话就像以上代码 就会误认为第15个引用 我们空下一格,然后在模式修正里忽略模式里的空格就能成功匹配 如果一个后向引用出现在它所引用的子组内部, 它的匹配就会失败 (a\1) 就不会得到任何匹配 而这种引用可以用于内部的子模式重复 (a|b\1)会匹配 ”a”但不会匹配b( 因为子组内部有一个可选路径,可选路径中有一条路能够完成匹配,在匹配完成后, 后向引用就能够引用到内容了)。 代码16: $p='#(a|b\1)+#';$str="abba";preg_match_all($p,$str,$arr);print_r($arr); 结果 在每次子模式的迭代过程中, 后向引用匹配上一次迭代时这个子组匹配到的字符串。为了做这种工作, 模式必须满足这样一个条件,模式在第一次迭代的时候, 必须能够保证不需要匹配后向引用。 这种条件可以像上面的例子用可选路径来实现,也可以通过使用最小值为 0 的量词修饰后向引用的方式来完成。 在 PHP 5.2.2之后, \g转义序列可以用于子模式的绝对和相对引用。 这个转义序列必须紧跟一个无符号数字或一个负数, 可以选择性的使用括号对数字进行包裹。 序列\1, \g1,\g{1} 之间是同义词关系。 这种用法可以消除使用反斜线紧跟数值描述反向引用时候产生的歧义。 这种转义序列有利于区分后向引用和八进制数字字符, 也使得后向引用后面紧跟一个原文匹配数字变的更明了,比如 \g{2}1。 代码17: $p='#([a-z]{2})\g{1}5#';$str="abab5";preg_match_all($p,$str,$arr);print_r($arr); 可与代码15对比 \g 转义序列紧跟一个负数代表一个相对的后向引用。比如: (foo)(bar)\g{-1} 可以匹配字符串 ”foobarbar”, (foo)(bar)\g{-2} 可以匹配 ”foobarfoo”。 这在长的模式中作为一个可选方案, 用来保持对之前一个特定子组的引用的子组序号的追踪。 代码18 $p='#(foo)(bar)\g{-1}#';$p1='#(foo)(bar)\g{-2}#';$str="foobarbar";$str1="foobarfoo";preg_match_all($p,$str,$arr);preg_match_all($p1,$str1,$arr1);print_r($arr);print_r($arr1); 结果: 后向引用也支持使用子组名称的语法方式描述, 比如 (?P=name) 或者 PHP 5.2.2 开始可以实用\k8a11bc632ea32a57b3e3693c7987c420 或 \k’name’。 另外在 PHP 5.2.4 中加入了对\k{name} 和 \g{name} 的支持。 代码19: $p="#(?'alpha'[a-z]{2})(?<digt>[0-9]{3})\k<digt>(?P=alpha)#";$str="aa123123aa";preg_match_all($p,$str,$arr);print_r($arr); 结果: 可与代码8比较着看 注意标红的 Alpha前一个有引号,后一个没有 P大写 参考资料:2d688e9f5d419a93fafe26b57316c315 未完待续.... |