1 前言
PHP被大量的应用于Web的后台CGI开发,一般是在用户数据数据以后得出某种结果,可是若是用户输入的数据不正确,就会出现问题,好比说某人的生日是"2月30日"!那应该怎么样来检验暑假是否正确呢? 在PHP中加入了正则表达式的支持,让咱们能够十分方便的进行数据匹配。
2 什么是正则表达式:
简单的说,正则表达式是一种能够用于模式匹配和替换的强大工具。在几乎全部的基于Unix/Linux系统的软件工具中找到正则表达式的痕迹,例如:Perl或PHP脚本语言。此外,&106avascript这种客户端的脚本语言也提供了对正则表达式的支持,如今正则表达式已经成为了一个通用的概念和工具,被各种技术人员所普遍使用。
在某个Linux网站上面有这样的话:"若是你问一下Linux爱好者最喜欢什么,他可能会回答正则表达式;若是你问他最惧怕什么,除了繁琐的安装配置外他确定会说正则表达式。"
正如上面说的,正则表达式看起来很是复杂,让人惧怕,大多数的PHP初学者都会跳过这里,继续下面的学习,可是PHP中的正则表达式有着能够利用模式匹配找到符合条件的字符串、判断字符串是否合乎条件或者用指定的字符串来替代符合条件的字符串等强大的功能,不学实在太惋惜了……
3 正则表达式的基本语法:
一个正则表达式,分为三个部分:分隔符,表达式和修饰符。
分隔符能够是除了特殊字符之外的任何字符(好比"/ !"等等),经常使用的分隔符是"/"。表达式由一些特殊字符(特殊字符详见下面)和非特殊的字符串组成,好比"[a-z0-9_-]+@[a-z0-9_-.]+"能够匹配一个简单的电子邮件字符串。修饰符是用来开启或者关闭某种功能/模式。下面就是一个完整的正则表达式的例子:
/hello.+?hello/is
上面的正则表达式"/"就是分隔符,两个"/"之间的就是表达式,第二个"/"后面的字符串"is"就是修饰符。
在表达式中若是含有分隔符,那么就须要使用转义符号"\",好比"/hello.+?\/hello/is"。转义符号除了用于分隔符外还能够执行特殊字符,所有由字母构成的特殊字符都须要"\"来转义,好比"\d"表明全体数字。
4 正则表达式的特殊字符:
正则表达式中的特殊字符分为元字符、定位字符等等。
元字符是正则表达式中一类有特殊意义的字符,用来描述其前导字符(即元字符前面的字符)在被匹配的对象中出现的方式。元字符自己是一个个单一的字符,可是不一样或者相同的元字符组合起来能够构成大的元字符。
元字符:
大括号:大括号用来精确指定匹配元字符出现的次数,例如"/pre{1,5}/"表示匹配的对象能够是"pre"、"pree"、"preeeee"这样在"pr"后面出现1个到5个"e"的字符串。或者"/pre{,5}/"表明pre出现0此到5次之间。
加号:"+"字符用来匹配元字符前的字符出现一次或者屡次。例如"/ac+/"表示被匹配的对象能够是"act"、"account"、"acccc"等在"a"后面出现一个或者多个"c"的字符串。"+"至关于"{1,}"。
星号:"*"字符用来匹配元字符前的字符出现零次或者屡次。例如"/ac*/"表示被匹配的对象能够是"app"、"acp"、"accp"等在"a"后面出现零个或者多个"c"的字符串。"*"至关于"{0,}"。
问号:"?"字符用来匹配元字符前的字符出现零次或者1次。例如"/ac?/"表示匹配的对象能够是"a"、"acp"、"acwp"这样在"a"后面出现零个或者1个"c"的字符串。"?"在正则表达式中还有一个很是重要的做用,即"贪婪模式"。
还有两个很重要的特殊字符就是"[ ]"。他们能够匹配"[]"之中出现过的字符,好比"/[az]/"能够匹配单个字符"a"或者"z";若是把上面的表达式改为这样"/[a-z]/",就能够匹配任何单个小写字母,好比"a"、"b"等等。
若是在"[]"中出现了"^",表明本表达式不匹配"[]"内出现的字符,好比"/[^a-z]/"不匹配任何小写字母!而且正则表达式给出了几种"[]"的默认值:
[:alpha:]:匹配任何字母
[:alnum:]:匹配任何字母和数字
[:digit:]:匹配任何数字
[:space:]:匹配空格符
[:upper:]:匹配任何大写字母
[:lower:]:匹配任何小写字母
[:punct:]:匹配任何标点符号
[:xdigit:]:匹配任何16进制数字
另外下面这些特殊字符在转义符号"\"转义后表明的含义以下:
s:匹配单个的空格符
S:用于匹配除单个空格符以外的全部字符。
d:用于匹配从0到9的数字,至关于"/[0-9]/"。
w:用于匹配字母,数字或下划线字符,至关于"/[a-zA-Z0-9_]/"。
W:用于匹配全部与w不匹配的字符,至关于"/[^a-zA-Z0-9_]/"。
D:用于匹配任何非10进制的数字字符。
.:用于匹配除换行符以外的全部字符,若是通过修饰符"s"的修饰,"."能够表明任意字符。
利用上面的特殊字符能够很方便的表达一些比较繁琐的模式匹配。例如"/\d0000/"利用上面的正则表达式能够匹配万以上,十万一下的整数字符串。
定位字符:
定位字符是正则表达式中又一类很是重要的字符,它的主要做用是用于对字符在匹配对象中的位置进行描述。
^:表示匹配的模式出如今匹配对象的开头(和在"[]"里面不一样)
$:表示匹配的模式出如今匹配对象的末尾
空格:表示匹配的模式出如今开始和结尾的两个边界之一
"/^he/":能够匹配以"he"字符开头的字符串,好比hello、height等等;
"/he$/":能够匹配以"he"字符结尾的字符串即she等;
"/ he/":空格开头,和^的做用同样,匹配以he开头的字符串;
"/he /":空格结束,和$的做用同样,匹配以he结尾的字符串;
"/^he$/":表示只和字符串"he"匹配。
括号:
正则表达式除了能够用户匹配,还能够用括号"()"来记录须要的信息,储存起来,给后面的表达式读取。好比:
/^([a-zA-Z0-9_-]+)@([a-zA-Z0-9_-]+)(.[a-zA-Z0-9_-])$/
就是记录邮件地址的用户名,和邮件地址的服务器地址(形式为username@server.com之类的),在后面若是想要读取记录下来的字符串,只是须要用"转义符+记录的次序"来读取。好比"\1"就至关于第一个"[a-zA-Z0-9_-]+","\2"至关于第二个([a-zA-Z0-9_-]+),"\3"就是第三个(.[a-zA-Z0-9_-])。可是在PHP中,"\"是一个特殊的字符,须要转义,因此""到了PHP的表达式中就应该写成"\\1"。
其余特殊符号:
"|":或符号"|"和PHP里面的或同样,不过是一个"|",而不是PHP的两个"||"!意思就是能够是某个字符或者另外一个字符串,好比"/abcd|dcba/"可能匹配"abcd"或者"dcba"。
5 贪婪模式:
前面在元字符中提到过"?"还有一个重要的做用,即"贪婪模式",什么是"贪婪模式"呢?
好比咱们要匹配以字母"a"开头字母"b"结尾的字符串,可是须要匹配的字符串在"a"后面含有不少个"b",好比"a bbbbbbbbbbbbbbbbb",那正则表达式是会匹配第一个"b"仍是最后一个"b"呢?若是你使用了贪婪模式,那么会匹配到最后一个"b",反之只是匹配到第一个"b"。
使用贪婪模式的表达式以下:
/a.+?b/
/a.+b/U
不使用贪婪模式的以下:
/a.+b/
上面使用了一个修饰符U,详见下面的部分。
6 修饰符:
在正则表达式里面的修饰符能够改变正则的不少特性,使得正则表达式更加适合你的须要(注意:修饰符对于大小写是敏感的,这意味着"e"并不等于"E")。正则表达式里面的修饰符以下:
i :若是在修饰符中加上"i",则正则将会取消大小写敏感性,即"a"和"A" 是同样的。 m:默认的正则开始"^"和结束"$"只是对于正则字符串若是在修饰符中加上"m",那么开始和结束将会指字符串的每一行:每一行的开头就是"^",结尾就是"$"。 s:若是在修饰符中加入"s",那么默认的"."表明除了换行符之外的任何字符将会变成任意字符,也就是包括换行符! x:若是加上该修饰符,表达式中的空白字符将会被忽略,除非它已经被转义。 e:本修饰符仅仅对于replacement有用,表明在replacement中做为PHP代码。 A:若是使用这个修饰符,那么表达式必须是匹配的字符串中的开头部分。好比说"/a/A"匹配"abcd"。 E:与"m"相反,若是使用这个修饰符,那么"$"将匹配绝对字符串的结尾,而不是换行符前面,默认就打开了这个模式。 U:和问号的做用差很少,用于设置"贪婪模式"。 7 PCRE相关的正则表达式函数: PHP的Perl兼容正则表达式提供的多个函数,分为模式匹配,替换和匹配数目等等: 一、preg_match : 函数格式:int preg_match(string pattern, string subject, array [matches]); 这个函数会在string中使用pattern表达式来匹配,若是给定了[regs],就会将string记录到[regs][0]中,[regs][1]表明使用括号"()"记录下来的第一个字符串,[regs][2]表明记录下来的第二个字符串,以此类推。preg若是在string中找到了匹配的pattern,就会返回"true",不然返回"false"。 二、preg_replace : 函数格式:mixed preg_replace(mixed pattern, mixed replacement, mixed subject); 这个函数会使用将string中符合表达式pattern的字符串所有替换为表达式replacement。若是replacement中须要包含pattern的部分字符,则可使用"()"来记录,在replacement中只是须要用"\1"来读取。 三、preg_split : 函数格式:array preg_split(string pattern, string subject, int [limit]); 这个函数和函数split同样,区别仅在与split可使用简单正则表达式来分割匹配的字符串,而preg_split使用彻底的Perl兼容正则表达式。第三个参数limit表明容许返回多少个符合条件的值。 四、preg_grep : 函数格式:array preg_grep(string patern , array input); 这个函数和preg_match功能基本上,不过preg_grep能够将给定的数组input中的全部元素匹配,返回一个新的数组。 下面举一个例子,好比咱们要检查Email地址的格式是否正确: function emailIsRight($email) { if (preg_match("^[_\.0-9a-z-]+@([0-9a-z][0-9a-z-]+\.)+[a-z]{2,3}$",$email)) { return 1; } return 0; } if(emailIsRight('y10k@963.net')) echo '正确 '; if(!emailIsRight('y10k@fffff')) echo '不正确 '; ?> 上面的程序会输出"正确 不正确"。 8.PHP中的Perl兼容正则表达式和Perl/Ereg正则表达式的区别: 虽然叫作“Perl兼容正则表达式”,可是和Perl的正则表达式相比,PHP的仍是由一些不一样,好比修饰符“G”在Perl里面表明所有匹配,可是在PHP中没有加入对这个修饰符的支持。 还有就是和ereg系列函数的区别,ereg也是PHP中提供的正则表达式函数,不过和preg相比,要弱上不少。 一、ereg里面是不须要也不能使用分隔符和修饰符的,因此ereg的功能比preg要弱上很多。 二、关于".":点在正则里面通常是除了换行符之外的所有字符,可是在ereg里面的"."是任意字符,即包括换行符!若是在preg里面但愿"."可以包括换行符,能够在修饰符中加上"s"。 三、ereg默认使用贪婪模式,而且不能修改,这个给不少替换和匹配带来麻烦。 四、速度:这个或许是不少人关心的问题,会不会preg功能强大是以速度来换取的?不用担忧,preg的速度要远远比ereg快,笔者作了一个程序测试: time test: PHP代码: echo "Preg_replace used time:"; $start = time(); for($i=1;$i<=100000;$i++) { $str = "ssssssssssssssssssssssssssss"; preg_replace("/s/","",$str); } $ended = time()-$start; echo $ended; echo " ereg_replace used time:"; $start = time(); for($i=1;$i<=100000;$i++) { $str = "ssssssssssssssssssssssssssss"; ereg_replace("s","",$str); } $ended = time()-$start; echo $ended; echo " str_replace used time:"; $start = time(); for($i=1;$i<=100000;$i++) { $str = "sssssssssssssssssssssssssssss"; str_replace("s","",$str); } $ended = time()-$start; echo $ended; ?> 结果: Preg_replace used time:5 ereg_replace used time:15 str_replace used time:2 str_replace由于不须要匹配因此速度很是快,而preg_replace的速度比ereg_replace要快上很多。 9.关于PHP3.0对于preg的支持: 在PHP 4.0中默认加入了preg支持,可是在3.0中确没有。若是在3.0中但愿使用preg函数,必须加载php3_pcre.dll文件,只要在php.ini的extension部分设置加入"extension = php3_pcre.dll"而后重新启动PHP就能够了! 其实正则表达式还经常使用于UbbCode的实现,不少PHP论坛都使用了这个方法(好比zForum zphp.com或者VB vbullent.com),可是具体的代码比较长。