php中正则表达式详解
概述
正则表达式是⼀种描述字符串结果的语法规则,是⼀个特定的格式化模式,可以匹配、替换、截取匹配的字符串。常⽤的语⾔基本上都有正则表达式,如JavaScript、java等。其实,只有了解⼀种语⾔的正则使⽤,其他语⾔的正则使⽤起来,就相对简单些。⽂本主要围绕解决下⾯问题展开。
有哪些常⽤的转义字符
什么是限定符与定位符
什么是单词定位符
特殊字符有哪些
什么是逆向引⽤以及怎样使⽤逆向引⽤
匹配模式
php中怎样使⽤正则表达式
php中哪些⽅⾯需要⽤到正则
怎样进⾏邮箱匹配,url匹配,⼿机匹配
怎样使⽤正则替换字符串中某些字符
贪婪匹配与惰性匹配区别
正则表达式之回溯与固态分组
正则优缺点有哪些
正则表达式的基本知识汇总
⾏定位符(^与$)
⾏定位符是⽤来描述字符串的边界。“$”表⽰⾏结尾“^”表⽰⾏开始如"^de",表⽰以de开头的字符串"de$",表⽰以de结尾的字符串。
单词定界符
我们在查的⼀个单词的时候,如an是否在⼀个字符串”gril and body”中存在,很明显如果匹配的话,an肯定是可以匹配字符串“gril and body”匹配到,怎样才能让其匹配单词,⽽不是单词的⼀部分呢?这时候,我们可以是哟个单词定界符\b。
\ban\b 去匹配”gril and body”的话,就会提⽰匹配不到。
当然还有⼀个⼤写的\B,它的意思,和\b正好相反,它匹配的字符串不能使⼀个完整的单词,⽽是其他单词或字符串中的⼀部分。如\Ban\B。
选择字符(|) ,表⽰或
选择字符表⽰或的意思。如Aa|aA,表⽰Aa或者是aA的意思。注意使⽤”[]”与”|”的区别,在于”[]”只能匹配单个字符,⽽”|”可以匹配任意长度的字符串。在使⽤”[]”的时候,往往配合连接字符”-“⼀起使⽤,如[a-d],代表a或b或c或d。
排除字符,排除操作
正则表达式提供了”^”来表⽰排除不符合的字符,^⼀般放在[]中。如[^1-5],该字符不是1~5之间的数字。
限定符(?*+{n,m})
限定符主要是⽤来限定每个字符串出现的次数。
限定字符含义
?零次或⼀次
*零次或多次
+⼀次或多次
{n}n次
{n,}⾄少n次
{n,m}n到m次
如(D+)表⽰⼀个或多个D
点号操作符
匹配任意⼀个字符(不包含换⾏符)
表达式中的反斜杠(\)
表达式中的反斜杠有多重意义,如转义、指定预定义的字符集、定义断⾔、显⽰不打印的字符。
转义字符
转义字符主要是将⼀些特殊字符转为普通字符。⽽这些常⽤特殊字符有”.”,”?”、”\”等。
指定预定义的字符集
字符含义
\d任意⼀个⼗进制数字[0-9]
\D任意⼀个⾮⼗进制数字
\s任意⼀个空⽩字符(空格、换⾏符、换页符、回车符、字表符)
\S任意⼀个⾮空⽩字符
\w任意⼀个单词字符
\W任意个⾮单词字符
###显⽰不可打印的字符
字符含义
\a报警
\b退格
\f换页
\n换⾏
\r回车
\t字表符
括号字符()
在正则表达式中⼩括号的作⽤主要有:
改变限定符如(|、* 、^)的作⽤范围
如(my|your)baby,如果没有”()”,|将匹配的是要么是my,要么是yourbaby,有了⼩括号,匹配的就是mybaby或yourbaby。
进⾏分组,便于反向引⽤
反向引⽤
反向引⽤,就是依靠⼦表达式的”记忆”功能,匹配连续出现的字串或是字符。如(dqs)(pps)\1\2,表⽰匹配字符串dqsppsdqspps。在下⾯php应⽤中,我将详细展开学习反向引⽤。
模式修饰符
模式修饰符的作⽤是设定模式,也就是正则表达式如何解释。php中主要模式如下表:
修饰符说明
i忽略⼤⼩写
m多⽂本模式
s单⾏⽂本模式
php实例代码详解x忽略空⽩字符
正则表达式在php中应⽤
php中字符串匹配
所谓的字符串匹配,⾔外之意就是判断⼀个字符串中,是否包含或是等于另⼀个字符串。如果不使⽤正则,我们可以使⽤php中提供了很多⽅法进⾏这样的判断。
不使⽤正则匹配
strstr函数
string strstr ( string haystack,mixedneedle [, bool $before_needle = false ])
注1:haystack是当事字符串,needle是被查的字符串。该函数区分⼤⼩写。
注2:返回值是从needle开始到最后。
注3:关于$needle,如果不是字符串,被当作整形来作为字符的序号来使⽤。
注4:before_needle若为true,则返回前东西。
stristr函数与strstr函数相同,只是它不区分⼤⼩写
strpo函数
int strpos ( string haystack,mixedneedle [, int $offset = 0 ] )
注1:可选的 offset 参数可以⽤来指定从 haystack 中的哪⼀个字符开始查。返回的数字位置是相对于 haystack 的起始位置⽽⾔的。
stripos -查字符串⾸次出现的位置(不区分⼤⼩定)
strrpos -计算指定字符串在⽬标字符串中最后⼀次出现的位置
strripos -计算指定字符串在⽬标字符串中最后⼀次出现的位置(不区分⼤⼩写)
使⽤正则进⾏匹配
在php中,提供了preg_math()和preg_match_all函数进⾏正则匹配。关于这两个函数原型如下:
int preg_match|preg_match_all ( string $pattern , string $subject [, array &$matches [, int $flags = 0 [, int $offset = 0 ]]] )
搜索subject与pattern给定的正则表达式的⼀个匹配.
pattern:要搜索的模式,字符串类型。
subject :输⼊字符串。
matches:如果提供了参数matches,它将被填充为搜索结果。 matches[0]将包含完整模式匹配到的⽂本,matches[1]将包含第⼀个捕获⼦组匹配到的⽂本,以此类推。
flags:flags可以被设置为以下标记值:PREG_OFFSET_CAPTURE 如果传递了这个标记,对于每⼀个出现的匹配返回时会附加字符串偏移量(相对于⽬标字符串的)。注意:这会改变填充到matches参数的数组,使其每个元素成为⼀个由第0个元素是匹配到的字符串,第1个元素是该匹配字符串在⽬标字符串subject中的偏移量。
offset:通常,搜索从⽬标字符串的开始位置开始。可选参数 offset ⽤于指定从⽬标字符串的某个未知开始搜索(单位是字节)。
返回值:preg_match()返回 pattern 的匹配次数。它的值将是0次(不匹配)或1次,因为 preg_match()在第⼀次匹配后将会停⽌搜索。 preg_match_all()不同于此,它会⼀直搜索subject直到到达结尾。如果发⽣错误 preg_match()返回 FALSE。
实例
实例1
判断字符串”“中是否包含csdn?
解法⼀(不适⽤正则):
如果不适⽤正则,我们使⽤strstr或者strpos中任意⼀个都可以,在此,我将使⽤strstr函数,代码如下:
$str='blog.csdn/hsd2012';
function checkStr1($str,$str2)
{
return strstr1($str,$str2)?true:false;
}
echo checkStr($str,'csdn');
解法⼆:使⽤正则
因为我们只需要判断是否存在即可,所以选择preg_match。
$str='blog.csdn/hsd2012';
$pattern='/csdn/';
function checkStr2($str,$str2)
{
return preg_match($str2,$str)?true:false;
}
echo checkStr2($str,$pattern);
实例2(考察单词定界符)
判断字符串”I am a good boy”中是否包含单词go
⾸先判断是单词,⽽不是字符串,因此⽐较的时候,需要⽐较是否包含’ go ‘,即在字符串go前后有⼀个空格。
解析:如果使⽤⾮正则⽐较,只需要调⽤上⾯的checkStr1()函数即可,注意,第⼆个参数前后要加⼀个空格,即’ go ‘。如果使⽤正则,
我们可以考虑使⽤单词定界符\b,那么$pattern=’/\bgo\b/’;然后调⽤checkStr2函数即可.
例3(考察反向引⽤)
判断字符串”I am a good boy”中是否包含3个相同的字母
解析:此时,如果我们不使⽤正则,将会很难判断,因为字母太多了,我们不可能去将所有字母分别与该字符串⽐较,那样⼯作量也⽐较⼤。这时候涉及到了正在的反向引⽤。在php正则表达式中,通过\n,来表⽰第n次匹配到的结果。如\5代表第五次匹配到的结果。那么本题的$pattern='/(\w).*\1.*\1/';
主要注意的是,在使⽤反向匹配的时候都需要使⽤(),反向匹配时,匹配()⾥⾯出现的字符或字符串。
php中字符串替换
不使⽤正则
php中当替换字符串的时候,如果不适⽤正则,我们通常使⽤substr、mb_substr、str_replace、substr_replace关于这⼏个函数区别如下表。
函数符功能描述
str_replace(find,replace,string,count)使⽤⼀个字符串替换字符串中的另⼀些字
符。find 必需。规定要查的值。replace 必需。规定替换 find 中的值的值。string 必需。
规定被搜索的字符串。count 可选。⼀个变量,对替换数进⾏计数。
substr_replace(string,replacement,start,length)把字符串的⼀部分替换为另⼀个字符串。
适合⽤于替换⾃定位置的字符串。string 必需。规定要检查的字符串。replacement 必需。规定要插⼊的字符串。start 必
需。规定在字符串的何处开始替换。
使⽤正则
如果使⽤正则替换,php中提供了preg_replace _callback和preg_replace 函数,preg_replace 原型如下:
mixed preg_replace ( mixed pattern,mixedreplacement , mixed subject[,intlimit = -1 [, int &count]])函数功能描述:在字符串subject中,查pattern,然后使⽤replacement 去替
换,如果
有limit则代表限制替换limit次。pregreplacecallback与pregreplace功能相识,不同的是pregreplaceback使⽤⼀个回调函数callback来代替replacement.−例1将字符串”hello,中国”中的hello替换为中国’;
str=strreplace(′hello′,′你好′,str)
或是使⽤str=substrreplace(str,’你好’,0,5)
使⽤正则
pattern=′/hello/′;str=preg_replace (pattern,′你好′,str);
-
例2
去除字符串”gawwenngeeojjgegop”中连续相同的字母
$str='gawwenngeeojjgegop';
$pattern='/(.)\1/';
$str=preg_replace($pattern,'',$str);
解析:当然这样可能会遇到,当第⼀次去除了重复了字符串后,⼜出来重复的字符串。如字符串味’gewwenngeeojjgegop’,针对这中问题,当然,这样的话,通过判断,继续替
换下去。
例3
将字符串中”age13gegep3iorji65k65k”;中出现的连续两个数字改为第⼆个数字,如字符串中13被改为3
$str='age13gegep3iorji65k65k';
$pattern='/(\d)(\d)/';
$str=preg_replace($pattern,'$2', $str);
解析:$n在正则表达式外使⽤反向引⽤。n代表第⼏次匹配到的结果。
php中字符串分割
不适⽤正则
php提供了explode函数去分割字符串,与其对应的是implode。关于explode原型如下:
array explode ( string delimiter,stringstring [, int $limit ] )
delimiter:边界上的分隔字符。
string:输⼊的字符串。
limit:如果设置了 limit 参数并且是正数,则返回的数组包含最多 limit 个元素,⽽最后那个元素将包含 string 的剩余部分。如果 limit 参数是负数,则返回除了最后的 -limit 个元素
外的所有元素。如果 limit 是 0,则会被当做 1。
使⽤正则
关于通过正则表达式进⾏字符串分割,php提供了split、preg_split 函数。preg_split() 函数,通常是⽐ split() 更快的替代⽅案。
array preg_split ( string pattern,stringsubject [, int limit=−1[,intflags = 0 ]] )
例题
将字符串 ‘‘按照’/’进⾏分割
解法⼀:
$str='blog.csdn/hsd2012/article/details/51152810';
$str=explode('/', $str);
解法⼆:
$str='blog.csdn/hsd2012/article/details/51152810';
$pattern='/\//';  /*因为/为特殊字符,需要转移*/
$str=preg_split ($pattern, $str);
php中贪婪匹配与惰性匹配
贪婪匹配:就是匹配尽可能多的字符。
⽐如,正则表达式中m.*n,它将匹配最长以m开始,n结尾的字符串。如果⽤它来搜索manmpndegenc的话,它将匹配到的字符串是manmpndegen⽽⾮man。可以这样
想,当匹配到m的时候,它将从后⾯往前匹配字符n。
懒惰匹配:就是匹配尽可能少的字符。
有的时候,我们需要并不是去贪婪匹配,⽽是尽可能少的去匹配。这时候,就需要将其转为惰性匹配。怎样将⼀个贪婪匹配转为惰性匹配呢?只需要在其后⾯添加⼀
个”?”即可。如m.*?n将匹配manmpndegenc,匹配到的字符串是man。
函数符描述
*?零次或多次,但尽可能少的匹配
+?⼀次或多次,但尽可能少的匹配
??0次或1次,但尽可能少的匹配
{n,}?⾄少n次,但尽可能少的匹配
{n,m}?n到m次,但尽可能少的匹配
php正则表达式之回溯与固态分组
回溯
⾸先我们需要清楚什么是回溯,回溯就像是在⾛岔路⼝,当遇到岔路的时候就先在每个路⼝做⼀个标记。如果⾛了死路,就可以照原路返回,直到遇见之前所做过的标记,标记
着还未尝试过的道路。如果那条路也⾛不能,可以继续返回,到下⼀个标记,如此重复,直到到出路,或者直到完成所有没有尝试过的路。⾸先我们看例题
$str='aageacwgewcaw';
$pattern='/a\w*c/i';
$str=preg_match($pattern, $str);
看到上⾯的程序,可能都清楚是什么意思,就是匹配$str是否包含这样⼀个由”a+0个或多个字母+c”不区分⼤⼩写的字符串。但是⾄于程序怎样去匹配的呢?匹配的过程中,回溯
了多少次呢?
匹配过程接下来操作描述
‘a\w*c’中a匹配到’aageacwgewcaw’中第⼀个字符a\w进⾏下⼀个字符匹配
因为\w是贪婪匹配,会⼀直匹配到’aageacwgewcaw’中最后⼀个字符w c进⾏下⼀个字符匹配时
‘a\w*c’中c发现没有可以匹配的于是\w匹配进⾏第⼀次回溯,匹配到倒数第⼆个字符a
‘a\w*c’中c发现还是没有可以匹配的于是\w匹配进⾏第⼆次回溯,匹配到倒数第三个字符c
‘a\w*c’中c匹配成功匹配结束返回结果
现在,如果我们将pattern改为pattern=’/a\w*?c/i’;⼜会回溯多少次呢?正确答案是回溯四次。
固态分组
固态分组,⽬的就是减少回溯次数,使⽤(?>…)括号中的匹配时如果产⽣了备选状态,那么⼀旦离开括号便会被⽴即引擎抛弃掉。举个典型的例⼦如: ‘\w+:’这个表达式在进⾏匹配时的流程是这样的,会优先去匹配所有的符合\w的字符,假如字符串的末尾没有’:’,即匹配没有到冒号,此时触发回溯机制,他会迫使前⾯的\w+释放字符,并且在交还的字符中重新尝试与’:’作⽐对。但是问题出现在这⾥: \w是不包含冒号的,显然⽆论如何都不会匹配成功,可是依照回溯机制,引擎还是得硬着头⽪往前,这就是对资源的浪费。所以我们就需要避免这种回溯,对此的⽅法就是将前⾯匹配到的内容固化,不令其存储备⽤状态!,那么引擎就会因为没有备⽤状态可⽤⽽只得结束匹配过程。⼤⼤减少回溯的次数。
如下代码,就不会进⾏回溯:
$str='nihaoaheloo';
$pattern='/(?>\w+):/';
$rs=preg_match($pattern, $str);
当然有的时候,⼜需慎⽤固态分组,如下,我要检查$str中是否包含以a结尾的字符串,很明显是包含的,但是因为使⽤了固态分组,反⽽达不到我们想要的效果
$str='nihaoahelaa';
$pattern1='/(?>\w+)a/';
$pattern2='/\w+a/';
$rs=preg_match($pattern1, $str);//0
$rs=preg_match($pattern2, $str);//1
php中其他常⽤字符串操作函数
字符串截取截取
string substr ( string string,intstart [, int length])stringmbsubstr(stringstr , int start[,intlength = NULL [, string $encoding = mb_internal_encoding() ]] )
字符串中⼤⼩写转换
strtoupper
strtolower
ucfirst
ucwords
字符串⽐较
-strcmp、strcasecmp、strnatcmp
字符串过滤
字符串翻转
strrev($str);
字符串随机排序
string str_shuffle ( string $str )
补充
怎样进⾏邮箱匹配,url匹配,⼿机匹配
使⽤preg_match函数进⾏匹配,以下内容从TP中复制⽽来。
邮箱验证
pattern=′/\w+([−+.]\w+)∗@\w+([−.]\w+)∗\.\w+([−.]\w+)∗/’;
url匹配
pattern='/^http(s?):\/\/(?:[A-za-z0-9-]+\.)+[A-za-z]{2,4}(:\d+)?(?:[\/\?#][\/=\?%\-&~`@[\]\':+!\.#\w]*)?/’;
⼿机验证
pattern=′/1[3458]\d10/’;
php中正则的优缺点
php中正则在某些时候,能帮我们解决php函数很多困难的匹配或是替换。然后php中正则的效率,往往是我们需要考虑的,所以在某些时候,能不⽤正则还是尽量不去⽤它,除⾮,某些场合必须⽤到,或是我们能够有效减少其回溯次数。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。