频道栏目
首页 > 资讯 > 语法 > 正文

php正则表达式在字符串处理中的应用

16-01-08        来源:[db:作者]  
收藏   我要投稿

初次接触正则表达式的人除了感觉它有些繁琐外,还会有一种深不可测的感觉。其实正则表达式就是描述字符排列模式的一种自定义的语法规则,在PHP给我们提供的系统函数中,使用这种模式对字符串进行匹配、查找、替换及分割等操作,它的应用非常广泛。例如,常见的使用正则表达式去验证用户在表单中提交的用户名、密码、E-mail地址、身份证号码及电话号码等格式是否合法;在用户发布文章时,将输入有URL的地方全部加上对应的链接;按所有标点符号计算文章中一共有多少个句子;抓取网页中某种格式的数据等等。

       正则表达式并不是PHP自己的产物,在很多领域都会见到它的应用,除了在Perl、C#及JAVA语言中应用外,在我们的B/S架构软件开发中,Linux操作系统、前台java script脚本、后台脚本PHP以及MySQL数据库中都可以应用到正则表达式。

正则表达式简介

       正则表达式也称为模式表达式,自身具有一套非常完整的、可以编写模式的语法体系,提供了一种灵活且直观的字符串处理方法。正则表达式通过构建具有特定规则的模式,与输入的字符串信息比较,从而实现字符串的匹配、查找、替换及分割等操作。

       不要被上例中看似乱码的字符串给吓退,它们就是按照正则表达式的语法规则构建的模式,是一种由普通字符和具有特殊功能的字符组成的字符串。而且要将这些模式字符串,放在特定的正则表达式函数中使用才有效果。学完本文以后就可以自由应用这样的代码了。

       在PHP中支持两套正则表达式的处理函数库。一套是由PCRE(Perl Compatible Regular Expression)库提供的,与Perl语言兼容的正则表达式函数。使用“preg_”为前缀命名的函数,而且表达式都应被包含在定界符中,如斜线(/)。另一套是由POSIX(Portable Operation System interface)扩展语法的正则表达式函数,使用以“ereg_”为前缀命名的。两套函数库的功能相似,执行效率稍有不同。一般而言,实现相同的功能,使用第一种PCRE库提供的正则表达式效率略占优势。所以在本文中主要介绍使用“preg_”为前缀命名的正则表达式函数。

正则表达式的语法规则

       正则表达式描述了一种字符串匹配的模式,通过这个模式在特定的函数中对字符串进行匹配、查找、替换及分割等操作。正则表达式作为一个匹配的模板,是由原子(普通字符,例如字符a到z)、有特殊功能的字符(称为元字符,例如*、+和?等)以及模式修正符三部分组成的文字模式。一个最简单的正则表达式模式中,至少也要包含一个原子,如“/a/”。而且在与Perl兼容的正则表达式函数中使用模式时,一定要给模式加上定界符,即将模式包含在两个反斜线“/”之间。一个HTML链接地址的正则表达式模式如下所示:

view source
 
print?
1 /<a.*?(?: |//t|//r|//n)?href=[/'"]?(.+?)[/'"]?(?:(?: |//t|//r|//n)+.*?)?>(.+?)<//a.*?>/sim
2 //获取链接地址

       在网页中任何属于HTML有效的链接标签,都可以和这个正则表达式的模式匹配上。该模式就用到了编写正则表达式模板的原子、元字符和模式休正符三个组成部分,将其拆分后如下所示:

              定界符是使用的是两个反斜线“/”,将模式放在它之间声明

              原子用到了<、a、href、=、'、"、/、>等普通字符和/t、/r、/n等转义字符

              元字符使用了[]、()、|、.、?、*、+等具有特殊含义的字符

              用到的模式修正符是在定界符最后一个反斜线之后的三个字符“s”、“i”和“m”

       对于原子、元字符以及模式修正符的使用将在后面详细介绍。首先编写一个示例,了解一下正则表达式的应用。通过PHP中给我们提供的preg_match()函数,使用上例中定义的正则表达式模式。该函数有两个必选参数,第一个参数需要提供用户编写的正则表达式模式,第二个参数需要一个字符串。该函数的作用就是在第二个字符串参数中,搜索与第一个参数给出的正则表达式匹配的内容。如果匹配成功则返回真。代码如下所示:

view source
 
print?
1 <?php
2 $pattern='/<a.*?(?: |//t|//r|//n)?href=[/'"]?(.+?)[/'"]?(?:(?: |//t|//r|//n)+.*?)?>(.+?)<//a.*?>/sim';
3 $content="请进单击进入<a href='http://www.lampbrother.net'><A style="COLOR: #f70968; FONT-SIZE: 14px; TEXT-DECORATION: underline" href="http://php.lampbrother.net" target=_blank>LAMP兄弟连</A></a>技术社区。";
4     if(preg_match($pattern, $content)) {  //使用preg_match()函数进行正则表达式的模式匹配
5         echo "成功匹配,在第二个参数中包含有效的HTML链接标签字符串。";
6     } else {
7         echo "在第二个参数的字符串中搜索不到有效的HTML链接标签。";

       在上面的代码中,使用正则表达式的语法规则,定义一个匹配HTML中链接标签的模式并存放在变量$pattrn中。又定义了一个字符串变量$content,在字符串中如果包含有效的HTML链接标签,则使用preg_match()函数时,就可以按$pattrn模式所定义的格式搜索到链接标签。

 定界符

       在程序语言中,使用与Perl兼容的正则表达式,通常都需要将模式表达式放入定界符之间。作为定界的字符也不仅仅局限于使用反斜线“/”。除了字母、数字和正斜线“/”以处的任何字符都可以作为定界符号,例如“#”、“!”、“{}”和“|”等都是可以的。通常习惯都将模式表达式包含在两个反斜线“/”之间。下例是一些模式表达式的应用,如下所示:

 

view source
 
print?
1 /<///w+>/                //使用反斜线作为定界符号合法
2 |(/d{3})-/d+|Sm         //使用竖线“|”作为定界符号合法
3 !^(?i)php[34]!            //使用感叹号“!”作为定界符号合法
4 {^/s+(/s+)?$}           //使用花括号“{}”作为定界符号合法
5 /href='(.*)'               //非法定界符号,缺少结束定界符 
6 1-/d3-/d3-/d4|           //非法定界符号,缺少起始定界符

 

 原子

原子是正则表达式的最基本的组成单位,而且在每个模式中最少要包含一个原子。原子是由所有那些未显式指定为元字符的打印和非打印字符组成,包括所有的大写和小写字母字符、所有数字、所有标点符号以及一些其它符号。例如a~z、A~Z、0~9、双引号“””、单引号“’”等。

 元字符

       利用Perl正则表达式还可以做另一件有用的事情,这就是使用各种元字符来搜索匹配。所谓元字符,就是用于构建正则表达式的具有特殊含义的字符,例如的“*”、“+”、“?”等。如果要在正则表达式中包含元字符本身,使其失去特殊的含义则必须在前面加上“/”进行转义。

       构造正则表达式的方法和创建数学表达式的方法相似,就是用多种元字符与操作符将小的表达式结合在一起来创建更大的表达式。正则表达式的组件可以是单个的字符、字符集合、字符范围、字符间的选择或者所有这些组件的任意组合。元字符是组成正则表达式的最重要部分,下面将这些元字符分为几类分别讲解。

通用字符类型

       通用字符类型可以匹配相应类型中的一个字符,例如“/d”可以匹配数字类型中的任意一个十进制数字。共有6种通用字符类型,包括“/d”和“/D”、“/s”和“/S”、“/w”和“/W”。当然也可以使用原子表制定出这种通用字符类型,例如[0-9]和“/d”的功能一样,都可以匹配一个十进制数字。

 限定符

       限定符用来指定正则表达式的一个给定原子必须要出现多少次才能满足匹配。有“*”、“+”、“?”、“{n}”、“{n,}”以及“{n,m}”共6种限定符,他们之间的区别主要是重复匹配的次数不同。其中“*”、“+”和“{n, }”限定符都是贪婪的,因为它们会尽可能多的匹配文字。

       元字符“*”表示0次、1次或多次匹配其前的原子,也可以使用“{0,}”完成同样的匹配。同样“+”可以使用“{1,}”表示,以及“?”可以使用“{0,1}”表示。

边界限制

       用来限定字符串或单词的边界范围,以获得更准确的匹配结果。元字符“^”(或“/A”)和“$”(或“/Z”)分别指字符串的开始与结束,而“/b”用于描述字符串中每个单词的前或后边界,与之相反的元字符“/B”表示非单词边界。例如有一个字符串“this is a test”使用的边界限制如下所示:

view source
 
print?
1 /a/s*b/         //“/s”表示空白原子,可以匹配在a和b之间没有空白、一个或有多个空白情况
2 /a/d+b/        //可以匹配在a和b之间有一个或有多个数字的情况,如a2b、a34567b等
3 /a/W?b/        //可以匹配在a和b之间有一个或有没有特殊字符,如ab、a#b、a%b等
4 /ax{4}b/       //可以匹配在a和b之间必须有4个x的字符串,如axxxxb
5 /ax{2,}b/      //可以匹配在a和b之间至少要有2个x的字符串,如axxb、axxxxxxb等
6 /ax{2,4}b/     //可以匹配在a和b之间至少有2个和最多有4个x的字符串,如axxb、axxxb和axxxxb

 

 句号(.)

       在字符类之外,模式中的圆点可以匹配目标中的任何一个字符,包括不可打印字符。但不匹配换行符(默认情况下),相当于“[^/n]”(Unix系统)或“[^/r/n]”(Windows系统)。如果设定了模式修正符号“s”则圆点也会匹配换行符。处理圆点与处理音调符“^”和美元符“$”是完全独立的,唯一的联系就是它们都涉及到换行符。

       通常,可以使用“.*?”或“.+?”组合来匹配除换行符以外的任何字符串。

 模式选择符(|)

       竖线字符“|”用来分隔多选一模式,在正则表达式中匹配两个或更多的选择之一。例如,模式“LAMP|J2EE”表示可以匹配“LAMP”也可以匹配“J2EE”,因为元字符竖线“|”的优先级是最低的,所以并不是表示匹配“LAMP2EE”或“LAMPJ2EE”。也可以有更多的选择,例如模式“/Linux|Apache|MySQL|PHP/”表示可以从中任意匹配一组。

原子表([])

       使用原子表“[]”可以定义一组彼此地位平等的原子,且从原子表中仅选择一个原子进行匹配。

       还可以使用原子表“[^]”匹配除表内原子外的任意一个字符,通常称为排除原子表。

       另外,在原子表中可以使用负号“-”连接一组按ASCII码顺序排列的原子,能够简化书写。如下所示: 

view source
 
print?
1 /0[xX][0-9a-fA-F]+/     //可以匹配一个简单的十六进制数,如0x2f、0X3AE或0x4aB等

模式单元

       模式单元是使用元字符“()”将多个原子组成大的原子,被当作一个单元独立使用。与数学表达式中的括号作用类似,一个模式单元中的表达式将被优先匹配。

       在上面的例子中,紧接着“*”前的多个原子“very”用元字符“()”括起来被当作一个单元,所以原子“(very)”可以没有,也可以有一个或多个。

后向引用

       使用元字符“( )”标记的开始和结束多个原子,不仅是一个独立的单元,也是一个子表达式。这样,对一个正则表达式模式或部分模式两边添加圆括号将导致相关匹配存储到一个临时缓冲区中,可以被获取供以后使用。所捕获的每个子匹配都按照在正则表达式模式中从左至右所遇到的内容存储。存储子匹配的缓冲区编号从1开始,连续编号直至最大99个子表达式。每个缓冲区都可以使用“/n”访问,其中n为一个标识特定缓冲区的一位或两位十进制数。例如“/1”、“/2”、“/3”等的形式进行引用,在正则表达的模式中使用时还需要在前面再加上一个反斜线,将斜线再次转义。

       在上例中声明了两个正则表达式,用来匹配日期格式。如果使用第一种模式则在年、月及日之间的分隔符号可以是任意的特殊字符,完全可以不对应。但实际应用中日期格式之间的分隔符号必须是对应的,即年和月之间使用“-”,则月和日之间也要和前面的一样使用“-”。在上述中的第二个正则表达式就可以达到这种效果。这是因为模式“/W”加上了元字符括号“()”,结果已经被存储到缓冲区中。所以在第一个“(/W)”的位置使用“-”则下一个位置使用“/1”引用时,其匹配模式也必须是字符“-”。

       如需要使用模式单元而又不想存储匹配结果时,可以使用非捕获元字符 “?:”、“?=”或“?!'”来忽略对相关匹配的保存。在一些正则表达式中,使用非存储模式单元是必要的,可以改变其后向引用的顺序。如下所示: 

view source
 
print?
1 /(Windows)(Linux)//2OS/        //使用“/2”再次引用第二个缓冲区中的字符串“Linux”
2 /(?:Widows)(Linux)//1OS/       //使用“?:”忽略了第一个子表式的存储,所以“/1”引用的就是

  模式匹配的优先级

       在使用正则表达式时,需要注意匹配的顺序。通常相同优先级是从左到右进行运算,不同优先级的运算先高后低。

模式修正符

       模式修正符号在正则表达式定界符之外使用(最后一个反斜线“/”之后),例如“/php/i”。其中“/php/”是一个正则表达式的模式,而“i”就是修正此模式所使用的修正符号,用来在匹配时不区分大小写。模式修正符可以调整正则表达式的解释,扩展了正则表达式在匹配、替换等操作时的某些功能,而且模式修正符号也可以组合使用,更增强了正则表达式的处理能力。例如“/php/Uis”则是使用“U”、“i”和“s”三个模式修正符组合在一起使用。模式修正符对编写简洁而简小的表达式大有帮助,在下面的表格中,列出了一些常用的模式修正符及其功能说明。

       下面是几个简单的示例,用以说明上表中模式修正符的使用。在使用模式修正符时,其中的空格和换行被忽略,如果使用其它非模式修正字符会导致错误。如下所示:

       ¨         模式“/Web Server/ix”可以用来匹配字符串“webServer”,忽略大小写和空白。

       ¨         模式“/a.+?e/Uis”可以匹配字符串“abcdefgabcdefgabcdefg”中的“abcdefgabcdefgabcde”,而不是“abcde”,如果不加“U”修正符则匹配“abce”。这三个模式组合可以按贪婪匹配、忽略大小写匹配以及“.”可以匹配换行符号。

       ¨         模式“/^is/m”可以匹配字符串“this/nis/na/ntes”中的“is”,因为使用模式修正符“m”将字符串视为了多行,第二行的开头出现了“is”则匹配成功。默认的正则开始“^”和结束“$”将目标字符串作为单一的一“行”(甚至其中包含有换行符也是如此)。

相关TAG标签
上一篇: HTTP响应头拆分/CRLF注入详解
下一篇:PHP Global变量定义当前页面的全局变量实现探讨
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站