正则笔记
PHP正则操作相关
- 元字符
元字符 | 说明 | POSIX字符类 | 说明 |
\d | 任何一个数字字符,相当于[0-9] | [:alnum:] | 任何一个字母或数字,相当于[a-zA-Z0-9] |
\D | 任何一个非数字字符,相当于[^0-9] | [:alpha:] | 任何一个字母,相当于[a-zA-Z] |
\w | 任何字母字符(大小写均可),数字字符,下划线_字符,相当于[a-zA-Z0-9_] | [:blank:] | 空格或制表符,相当于[ \t] |
\W | 任何非字母字符(大小写均可),数字字符,下划线_字符,相当于[^a-zA-Z0-9_] | [:cntrl:] | ASCII控制字符(ASCII 0到31,再加上ASCII 127) |
[\b] | 回退(并删除)一个字符(Backspace键) | [:digit:] | 任何一个数字,相当于[0-9] |
\f | 换页符 | [:graph:] | 和[:print:] 一样,但不包括空格 |
\n | 换行符 | [:lower:] | 任何一个小写字母,相当于[a-z] |
\r | 回车符 | [:print:] | 任何一个可打印字符 |
\t | 制表符 | [:punct:] | 既不属于[:alnum:]也不属于[:cntrl:] 的任何一个字符,相当于 |
\v | 垂直制表符 | [:space:] | 任何一个空白字符,包括空格,相当于[\f\n\r\t\v ] |
\s | 任何一个空白字符,相当于[\f\n\r\t\v] | [:upper:] | 任何一个大写字母,相当于[A-Z] |
\S | 任何一个非空白字符,相当于[^\f\n\r\t\v] | [:xdigit:] | 任何一个十六进制数字,相当于[a-fA-F0-9] |
\x | 十六进制数值前缀 | ||
\0(零) | 八进制数值前缀 | ||
匹配数量元字符 | 说明 | ||
+ | 匹配至少一个,不配零个字符的情况,相当于{1,} | ||
* | 匹配零个或多个,相当于{0,} | ||
? | 匹配零个或一个,相当于{0,1} | ||
贪婪型元字符 | 说明 | 懒惰型元字符 | 说明 |
* | 贪婪型元字符,他们在进行匹配的时会从文本的开头一直匹配到末尾,而不是匹配到第一个时为止 | *? | 与贪婪型的行为模式恰好相反 |
+ | +? | ||
{n,} | {n,}? | ||
边界限定符 | 说明 | ||
\b | (单词边界)\b用来匹配一个单词的开始或结尾 | ||
\B | (单词边界)不匹配一个单词的边界(即非字母数字下划线) | ||
^ | (字符串边界)以什么开头 | ||
$ | (字符串边界)以什么结尾 | ||
(?m) | (分行匹配模式)分行匹配模式使得正则表达式引擎把行的分隔符当做一个字符串分隔符来对待.^不仅匹配正常的字符串开头,还将匹配行分隔符(换行符)后面的开始位置,$不仅匹配正常的字符串结尾,还将匹配行分隔符(换行符)后面的结束位置.在使用(?m)时,必须放在整个模式的最前面,此模式在下方有我的例子 |
- 回溯引用的使用---回溯引用引用的是前面的划分的子表达式,当前面的子表达式匹配到的是word的时候,回溯引用也为word,他们是相同的
/*回溯引用(前后一致匹配,以及替换引用)*/
1 $sImageurl = 'http://i3.meishichina.com/http://i3.meishichina.com/attachment/good/2015/05/13/201505131431525637778.jpg'; 2 $sImageurl = preg_replace('/(http:\/\/\w{2}\.[a-z]+\.com\/)\1(.*)/','$1$2',$sImageurl); 3 echo $sImageurl;//http://i3.meishichina.com/attachment/good/2015/05/13/201505131431525637778.jpg
1 /*回溯引用(前后一致匹配)的测试*/ 2 $sContent = file_get_contents('http://home.imeishi.com/blog/').'<h1>我是不是也会出来呢?</h6>'; 3 preg_match_all('/<[hH][1-6]>.*?<\/[hH][1-6]>/', $sContent, $arMatch1);#未使用回溯引用 4 var_dump(end($arMatch1[0])); 5 preg_match_all('/<([hH][1-6])>.*?<\/\1>/', $sContent, $arMatch2);#使用回溯引用 6 var_dump(end($arMatch2[0])); 7 string(37) "<h1>我是不是也会出来呢?</h6>" 8 string(36) "<h5>随时随地,美食天下</h5>"
- POSIX字符类的用法
1 <?php 2 $sUrl = 'http://www.meishichina.com/mofang/class/yipinshicai/page/2/'; 3 preg_match_all('/[[:alnum:]]+/', $sUrl, $arMatch); 4 print_r($arMatch); 5 Array 6 ( 7 [0] => Array 8 ( 9 [0] => http 10 [1] => www 11 [2] => meishichina 12 [3] => com 13 [4] => mofang 14 [5] => class 15 [6] => yipinshicai 16 [7] => page 17 [8] => 2 18 ) 19 20 ) 21 ?>
- 一个能在Unix/Linux和Windows上都能匹配空白行的正则
1 [\r]?\n[\r]?\n
- 贪婪和懒惰
1 /*测试贪婪型和懒惰型*/ 2 $sTxt = 'this offer is not available to cistomers living in <B>Ak</B> and <B>Hi</B>'; 3 preg_match_all('/<[Bb]>.+<\/[Bb]>/', $sTxt, $arMatch1);//贪婪型 4 print_r($arMatch1); 5 preg_match_all('/<[Bb]>.+?<\/[Bb]>/', $sTxt, $arMatch2);//懒惰型 6 print_r($arMatch2); 7 Array 8 ( 9 [0] => Array 10 ( 11 [0] => <B>Ak</B> and <B>Hi</B> 12 ) 13 14 ) 15 Array 16 ( 17 [0] => Array 18 ( 19 [0] => <B>Ak</B> 20 [1] => <B>Hi</B> 21 ) 22 23 )
- php分行匹配注释
1 匹配结果类似于这种的 2 /** 3 * 获取珍选下二级分类列表 4 * @author zhaoyingnan 2015/07/24 5 * @param string $param['classname'] 一级分类名称 6 * @param int $param['subid'] 二级分类id 7 * @param int $param['page'] 8 **/ 9 public function secondClassifyList($param) 10 11 //测试代码,可直接使用第二个,第一个是本人的文本中有特殊情况 12 $sContent = file_get_contents('/home/sunlibo/test/perl/zhen_action.php'); 13 preg_match_all('/(?m)^[\s]*\/\*\*.*[\r]?\n([\s]*\*.*[\r]?\n)*.*/', $sContent, $arMatch1); 14 preg_match_all('/(?m)^[\s]*\/\*\*.*[\r]?\n([\s]*\*.*[\r]?\n)*[\s]*p.*/', $sContent, $arMatch2); 15 print_r($arMatch1[0]); 16 print_r($arMatch2[0]);
- 子模式对于ip地址的匹配
1 /*子模式对于ip地址的测试*/ 2 $sString = '[12.159.46.200],[0.0.0.0],[255.255.255.255],[192.179.0.256],[992.168.3.257],[2.992.992.105],[2.92.902.1]'; 3 preg_match_all('/((([\d]{1,2})|(1[\d]{2})|(2[0-4][\d])|(25[0-5]))\.){3}([\d]{1,2}|(1[\d]{2})|(2[0-4][\d])|(25[0-5]))/', $sString, $arMatch1); 4 print_r($arMatch1[0]); 5 preg_match_all('/(((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))\.){3}((\d{1,2})|(1\d{2})|(2[0-4]\d)|(25[0-5]))/', $sString, $arMatch2); 6 print_r($arMatch2[0]); 7 Array 8 ( 9 [0] => 12.159.46.20 10 [1] => 0.0.0.0 11 [2] => 255.255.255.25 12 [3] => 192.179.0.25 13 [4] => 92.168.3.25 14 ) 15 Array 16 ( 17 [0] => 12.159.46.20 18 [1] => 0.0.0.0 19 [2] => 255.255.255.25 20 [3] => 192.179.0.25 21 [4] => 92.168.3.25 22 )
- 前后查找(也称为零宽度匹配)
前后查找中的前和后是与被查找的文本的相对位置而言的,左前右后原则;
前后查找其实就是一个子表达式罢了,向前查找就是以?=开头的子表达式,向后查找就是已?<=开头的子表达式;
前后查找匹配的内容并不会出现在最终结果里面;
?!是对向前查找的取非;
?<!是对向后查找的取非.
1 /*向前(后)查找匹配测试*/ 2 $sCss = ' 3 .bar-box li.bar-box-item-0{background:#848484} 4 .bar-add .bar-text{background:#ff8f30;color:#ddd;width:36px} 5 li.bar-box-item-1{background:#919191} 6 li.bar-box-item-2{background:#9d9d9d} 7 li.bar-box-item-3{background:#a9a9a9} 8 bar-text{background:#ff8721;color:#fff} 9 '; 10 //向前匹配类似于.bar-box 的内容,最后结果不包括空格 11 preg_match_all('/[.\w-]+(?=\s)/', $sCss, $arMatch1); 12 var_dump(current($arMatch1)); 13 //向后匹配类似于#a9a9a9的颜色内容,但是最终结果不包含# 14 preg_match_all('/(?<=#)[a-fA-F\d]{3,6}/', $sCss, $arMatch2); 15 print_r(current($arMatch2)); 16 17 array(2) { 18 [0]=> 19 string(8) ".bar-box" 20 [1]=> 21 string(8) ".bar-add" 22 } 23 Array 24 ( 25 [0] => 848484 26 [1] => ff8f30 27 [2] => ddd 28 [3] => 919191 29 [4] => 9d9d9d 30 [5] => a9a9a9 31 [6] => ff8721 32 [7] => fff 33 )
1 $sPrice = ' 2 ABC01: $23.45 3 HGG42: $5.31 4 CFMX1: $899.00 5 XTC99: $69.96 6 ZCC94: $6 7 TOTAL ITEMS FOUND: 4 8 '; 9 //向后匹配价格,最终结果不能包含$ 10 preg_match_all('/(?<=\$)[\d]+[.]?[\d]*/', $sPrice, $arMatch); 11 print_r(current($arMatch)); 12 13 Array 14 ( 15 [0] => 23.45 16 [1] => 5.31 17 [2] => 899.00 18 [3] => 69.96 19 [4] => 6 20 )
- 正则表达式里面的条件判断
回溯引用判断:(?(1)\s*<\/a>)只用?(1)为真的时候才会执行其后面的匹配\s*<\/a>,否则不往后匹配
1 /*正则表达式条件判断测试*/ 2 //回溯引用判断 3 $sHtml = ' 4 <ul> 5 <li> <a title="木木家常菜" target="_blank" href="http://home.meishichina.com/space-8271699.html"> <img width=540 height=200 class="imgLoad" src="http://static.meishichina.com/v6/img/blank.gif" data-src="http://i3.meishichina.com/attachment/magic/2015/07/21/20150721110355948431183.jpg"> </a> </li> 6 <li> <a title="叶子的小厨" target="_blank" href="http://home.meishichina.com/space-5987665.html"> <img width=540 height=200 class="imgLoad" src="http://static.meishichina.com/v6/img/blank.gif" data-src="http://i3.meishichina.com/attachment/magic/2015/07/21/20150721110324961950668.jpg"> </a> </li> 7 <li> <img width=540 height=200 class="imgLoad" src="http://static.meishichina.com/v6/img/blank.gif" data-src="http://i3.meishichina.com/attachment/magic/2015/07/21/20150721110205697095131.jpg"> </a></li> 8 </ul> 9 '; 10 preg_match_all('/(<a[\s]*[^>]+>\s*)?<img[\s]*[^>]+\/?>(?(1)\s*<\/a>)/', $sHtml, $arMatch); 11 print_r($arMatch); 12 13 Array 14 ( 15 [0] => <a title="木木家常菜" target="_blank" href="http://home.meishichina.com/space-8271699.html"> <img width=540 height=200 class="imgLoad" src="http://static.meishichina.com/v6/img/blank.gif" data-src="http://i3.meishichina.com/attachment/magic/2015/07/21/20150721110355948431183.jpg"> </a> 16 [1] => <a title="叶子的小厨" target="_blank" href="http://home.meishichina.com/space-5987665.html"> <img width=540 height=200 class="imgLoad" src="http://static.meishichina.com/v6/img/blank.gif" data-src="http://i3.meishichina.com/attachment/magic/2015/07/21/20150721110324961950668.jpg"> </a> 17 [2] => <img width=540 height=200 class="imgLoad" src="http://static.meishichina.com/v6/img/blank.gif" data-src="http://i3.meishichina.com/attachment/magic/2015/07/21/20150721110205697095131.jpg"> 18 ) 19 //可以看到最后一个并没有匹配</a>
前后条件判断:(?(?=-)-[\d]+)只有当(?(?=-))为真的时候-[\d]+才会执行
1 //前后查找条件判断,不匹配4567-这种的 2 $sNumber = ' 3 1232 4 1235-4565 5 4567- 6 5678 7 4569-789777 8 03123611656 9 0312-3611656 10 '; 11 preg_match_all('/([\d]{11})|([\d]{4}(?(?=-)-[\d]+))/', $sNumber, $arMatch); 12 print_r(current($arMatch)); 13 14 Array 15 ( 16 [0] => 1232 17 [1] => 1235-4565 18 [2] => 5678 19 [3] => 4569-789777 20 [4] => 03123611656 21 [5] => 0312-3611656 22 )
亲,自己研究下吧,(*^__^*)
1 //前后查找条件判断,不匹配带括号这种的电话号码 2 $sPhone = ' 3 010-3722069 4 0103722069 5 (010)3722069 6 (0315)3611656 7 03123611656 8 0312-3611656 9 '; 10 preg_match_all('/\s*[^\(]((\d{10,11})|(\b[\d]{3,4}(?(?=-)-[\d]+)\b))/', $sPhone, $arMatch2); 11 print_r(current($arMatch2)); 12 13 Array 14 ( 15 [0] => 16 010-3722069 17 [1] => 18 0103722069 19 [2] => 20 03123611656 21 [3] => 22 0312-3611656 23 )
但是其实上面的方法并不是很好的,仔细查看后就会发现上面那个也会010-37220618这个位数多于正确的电话号码,也会匹配0318)3787353中的0318,012)3722061中的012,所以最好采用下面的正则
1 $sTel = ' 2 010-3722069 3 010-37220618 4 0103722068 5 03123817117 6 03163611656 7 0312-3611655 8 (0315)3787354 9 0318)3787353 10 012)3722061 11 03163)611656 12 '; 13 preg_match_all('/[\s]*((\b[\d]{10,11}\b)|(\b[\d]{3}[-]\d{7}\b)|(\b[\d]{4}[-][\d]{7}\b))/', $sTel, $arMatch3); 14 print_r($arMatch3[0]); 15 16 Array 17 ( 18 [0] => 19 010-3722069 20 [1] => 21 0103722068 22 [2] => 23 03123817117 24 [3] => 25 03163611656 26 [4] => 27 0312-3611655 28 )
手机号码正则
1 <?php 2 var_dump(_validateMobile(17091310244)); 3 var_dump(_validateMobile(14591310244)); 4 var_dump(_validateMobile(18911937250)); 5 function _validateMobile($iPhone) 6 { 7 //电信号段:133/153/180/181/189/175/177 8 //联通号段:130/131/132/155/156/185/186/145/176 9 //移动号段:134/135/136/137/138/139/150/151/152/157/158/159/182/183/184/187/188/147/178 10 //虚拟运营商:170 11 if($iPhone) 12 { 13 preg_match('/^13\d{9}$|^14[57]\d{8}$|^15[012356789]\d{8}$|^17[05678]\d{8}$|^18\d{9}$/', $iPhone, $arMatch); 14 if($arMatch) 15 return 1; 16 } 17 return 0; 18 }