首先需要声明的是,其实我对正则的应用也不是特别地熟练,只不过是在工作中“被逼无奈”才一步步地对正则有了一些了解。随着对正则的了解越多,越来越发现正则表达式真的是一个很强有力的工具,使用正则,很多时候都可以事半功倍。
网上流传着很多通用的正则,比如说查找电话号码的正则,查找email的正则。相信也有很多朋友跟我一样,学习正则是从这些流行的正则开始的,当体会到了正则的强大,而这些流行的正则不再合用时,就有了学习正则的动力。其实正则的基本规则很简单,入门很容易,但入门之后怎么来使用却就是各有千秋了。目前PHP支持的正则共有两种:POSIX 扩展的正则表达式和perl兼容的正则表达式。很多PHP的教材上用的都是POSIX扩展的正则表达式,但我却更喜欢perl兼容的正则表达式,一来是因为可以有更好的兼容性,二来是我觉得perl兼容的正则表达式看上去更清晰。
先来假设一个工作环境:有一个包含用户信息的文件,共有一万行,每行记录一个用户的信息,格式如下:
username,010-12345678,firstname.lastname,05/21/2007
下面的文章里,我将以这个假设的工作环境来介绍PHP中perl兼容的正则表达式的查找和替换。
查找
最常用的查找是preg_match(),函数说明如下:
int preg_match_all ( string pattern, string subject, array matches [, int flags]
对正则表达式的语法就不多说了,我假设阅读这篇文章的朋友都有一定的正则基础。其实正则表达的查找用处并不是很大,不是太复杂的查找通过可以通过strstr()函数来现实,而且效率更高一些。使用正则的查找通常是一些用strstr()无法实现的比较复杂的查找。例如,我要查找电话号码的区号是010且lastname是bill的一行记录,就可以这么写
preg_match('/^[^,]*,010[^\.]*\.bill.*$/i',$line);
其中$line的意思是文件的一行数据。假如$line中的区号是010,lastname又正好是bill,上面的语句就会返回一个非零的正整数,通常我们并不关心这个数的值,而是只关心是否有匹配。又假如我们想找出lastname是bill的用户在2007年的记录,可以用下面的语句
preg_match('/^[^,]*,[^,]*,[^\.]*\.bill,[^\/]*\/[^\/]*\/2007/i',$line);
用到正则表达式的替换的地方通常是在需要匹配两个或两个以上的关键字,且这两个关键字不相邻。这个时候无法用正常的查找函数来实现,就用到正则。
替换:相对于查找,我认为替换才是正则表达式最强大、最有用的地方。假设我们现在需要把文件中一万条记录的日期格式换成yyyy/mm/dd,你会怎么做呢?你会发现,普通的查找替换是达不到这个目的了。也许你会说可以把一行的记录分解,进行分析后再重组。我承认这确实是一个解决的办法,可是这并不是最好的解决办法,让我们看一下用正则是怎么来达到我们的要求的:
$line = preg_replace('/([^,]*,[^,]*,[^,]*,)([0-9]*)\/([0-9]*)\/([0-9]*)/i',"\${1}\${4}\${2}\${3}",$line);
这里我们使用了正则表达式里的“子模式”,细心观察就可以发现,preg_replace函数的第一个参数里一共有四对‘()’,每一对‘()’里的内容就是一个“子模式”,在第二个参数里可以通过\${1}、\${2}这样的格式来随便组合这些子模式。如我想删除数据里的电话号码,可以这样来写:
$line = preg_replace('/([^,]*,)([^,]*,)[^,]*,)([0-9]*)\/([0-9]*)\/([0-9]*)/i',"\${1}\${4}\${2}\${3}",$line);
这里为了介绍子模式而使用了比较复杂的写法,实际上还有一种更简单的方法:
$line = preg_replace('/,[\d]+\-[\d]+/i','',$line);
先来假设一个工作环境:有一个包含用户信息的文件,共有一万行,每行记录一个用户的信息,格式如下:
username,010-12345678,firstname.lastname,05/21/2007
下面的文章里,我将以这个假设的工作环境来介绍PHP中perl兼容的正则表达式的查找和替换。
查找
最常用的查找是preg_match(),函数说明如下:
int preg_match_all ( string pattern, string subject, array matches [, int flags]
对正则表达式的语法就不多说了,我假设阅读这篇文章的朋友都有一定的正则基础。其实正则表达的查找用处并不是很大,不是太复杂的查找通过可以通过strstr()函数来现实,而且效率更高一些。使用正则的查找通常是一些用strstr()无法实现的比较复杂的查找。例如,我要查找电话号码的区号是010且lastname是bill的一行记录,就可以这么写
preg_match('/^[^,]*,010[^\.]*\.bill.*$/i',$line);
其中$line的意思是文件的一行数据。假如$line中的区号是010,lastname又正好是bill,上面的语句就会返回一个非零的正整数,通常我们并不关心这个数的值,而是只关心是否有匹配。又假如我们想找出lastname是bill的用户在2007年的记录,可以用下面的语句
preg_match('/^[^,]*,[^,]*,[^\.]*\.bill,[^\/]*\/[^\/]*\/2007/i',$line);
用到正则表达式的替换的地方通常是在需要匹配两个或两个以上的关键字,且这两个关键字不相邻。这个时候无法用正常的查找函数来实现,就用到正则。
替换:相对于查找,我认为替换才是正则表达式最强大、最有用的地方。假设我们现在需要把文件中一万条记录的日期格式换成yyyy/mm/dd,你会怎么做呢?你会发现,普通的查找替换是达不到这个目的了。也许你会说可以把一行的记录分解,进行分析后再重组。我承认这确实是一个解决的办法,可是这并不是最好的解决办法,让我们看一下用正则是怎么来达到我们的要求的:
$line = preg_replace('/([^,]*,[^,]*,[^,]*,)([0-9]*)\/([0-9]*)\/([0-9]*)/i',"\${1}\${4}\${2}\${3}",$line);
这里我们使用了正则表达式里的“子模式”,细心观察就可以发现,preg_replace函数的第一个参数里一共有四对‘()’,每一对‘()’里的内容就是一个“子模式”,在第二个参数里可以通过\${1}、\${2}这样的格式来随便组合这些子模式。如我想删除数据里的电话号码,可以这样来写:
$line = preg_replace('/([^,]*,)([^,]*,)[^,]*,)([0-9]*)\/([0-9]*)\/([0-9]*)/i',"\${1}\${4}\${2}\${3}",$line);
这里为了介绍子模式而使用了比较复杂的写法,实际上还有一种更简单的方法:
$line = preg_replace('/,[\d]+\-[\d]+/i','',$line);
有一句话,忘了是别人说的还是自己原创的,反正在我脑子里好久了:正则表达式不是技术,而是技巧:)正则的入门实际上是相当简单的,用上一两次就能掌握基本的语法,要让这把剑发挥出多大的威力,就看个人的修行了。需要说明的一点是,这把剑实际上也是一把双刃剑:正则的执行效率实际上要比strstr,strpos之类的函数低,所以,当你的查找很简单的时候,就没必要再合用正则了。
本文转自wfyang 51CTO博客,原文链接:http://blog.51cto.com/wfyang/28637
,如需转载请自行联系原作者