当前位置: 首页 > 文章教程  > 计算机与互联网 > 网络编程

21.4PHP中的PERL兼容正则表达式函数

9/17/2020 9:31:19 PM 人评论

21.4PHP中的PERL兼容正则表达式函数

21.4 PHP中的PERL兼容正则表达式函数

对PERL语言有所了解的读者,一定对PERL中正则表达式的强大功能印象深刻。PERL最初就是设计用来处理文本文件的一种语言,至今,PERL语言在处理文本方面的强大功能仍是无可比拟的,尤其在维护、分析系统数据方面,PREL语言扮演着不可替代的角色。

正是基于此,PHP中除了可以使用POSIX函数支持正则表达式之外,还可以使用PERL兼容的正则表达式函数。从PHP 4.0开始,包含了一个PERL兼容的正则表达式(PCRE)库,和正常的regex库一起与PHP绑定。另外,PCRE和PERL的正则表达式之间有一些细微差别,但这并不在本书讨论范围之内。本节就为读者介绍如何使用PERL兼容的正则表达式函数。

21.4.1 PERL兼容正则表达式中的修正符

所谓修正符,是指在正则表达式最后诸如/si之类的修正说明。这些修正符如下所述,括号中的名称是这些修正符的内部PCRE名。对于这个名称,读者可以不必过于关注。

·i(PCRE_CASELESS):匹配时忽略大小写。

·m(PCRE_MULTILINE):当设定了此修正符,行起始(^)和行结束($)除了匹配整个字符串开头和结束外,还分别匹配其中的换行符(\n)的之后和之前。

·s(PCRE_DOTALL):如果设定了此修正符,模式中的圆点元字符(.)匹配所有的字符,包括换行符。如没有此设定的话,则不包括换行符。

·x(PCRE_EXTENDED):如果设定了此修正符,模式中的空白字符除了被转义的或在字符类中的以外完全被忽略。

·e:如果设定了此修正符,preg_replace()在替换字符串中对逆向引用做正常的替换,将其作为PHP代码求值,并用其结果来替换所搜索的字符串。只有preg_replace()使用此修正符,其他PCRE函数将忽略之。

·A(PCRE_ANCHORED):如果设定了此修正符,模式被强制为“anchored”,即强制仅从目标字符串的开头开始匹配。

·D(PCRE_DOLLAR_ENDONLY):如果设定了此修正符,模式中的行结束($)仅匹配目标字符串的结尾。没有此选项时,如果最后一个字符是换行符,也会被匹配。如果设定了m修正符,则忽略此选项。

·S:当一个模式将被使用若干次时,为加速匹配而值得先对其进行分析。如果设定了此修正符则会进行额外的分析。目前,分析一个模式仅对没有单一固定起始字符的non-anchored模式有用。

·U(PCRE_UNGREEDY):使“?”的默认匹配成为贪婪状态的。

·X(PCRE_EXTRA):模式中的任何反斜线后面跟上一个没有特殊意义的字母导致一个错误,从而保留此组合以备将来扩充。默认情况下,一个反斜线后面跟一个没有特殊意义的字母被当成该字母本身。

·u(PCRE_UTF8):此修正符启用了一个PCRE中与PERL不兼容的额外功能。模式字符串被当成UTF-8。本修正符在UNIX下自PHP 4.1.0起可用,在Win32下自PHP 4.2.3起可用。自PHP 4.3.5起开始检查模式的UTF-8合法性。

21.4.2 返回与模式匹配的数组单元的正则表达式函数

从本小节开始讲述PERL兼容的正则表达式函数,这类函数中所使用的模式及其类似的PERL语言。表达式应被包含在定界符中,如斜线(/)。这就是说,正则表达式作为参数传入这些函数时,需要将正则表达式限定在//之内。例如/<\/\w+>/,而/href='(.*)'就不是一个合法的PERL兼容正则表达式,因为它缺少结束界定符/。任何不是字母、数字或反斜杠(\)的字符都可以作为界定符。如果作为界定符的字符必须被用在表达式本身中,则需要用反斜杠字符转义。

第一个要介绍的是函数preg_grep(),该函数返回与模式匹配的数组元素,语法如下。


array preg_grep (string $pattern, array $input [, int $flag])

该函数返回一个数组,其中包括参数$input数组中与给定的参数$pattern模式相匹配的元素。第3个参数$flag是可选的,如果其传入值为PREG_GREP_INVERT,那么函数preg_grep()会返回输入数组中不匹配给定pattern的单元。代码21-8演示了该函数的用法。

代码21-8 在程序中使用PERL兼容的正则表达式函数preg_grep()21-8.php


     01 <?php
     02 $test_preg = array(
     03 "AK47",
     04 "163.com",
     05 "happy new year!",
     06 "EX0000",
     07 "007 in USA",
     08 "abc123",
     09 "TEST-abc-315",
     10 "123654789",
     11 "Euapa00!"
     12 );                                              //
定义字符串数组
     13 
     14 echo "<b>
原数组:</b>";
     15 echo "<pre>";
     16 print_r($test_preg);
     17 echo "</pre>";
     18 
     19 $preg_arr = preg_grep("/^[A-Z].*[0-9]$/",$test_preg);
                                                        //
传入正则表达式给函数preg_grep()
     20 echo "<br>";
     21 echo "<b>
将原数组中以任意大写字母开头的、中间任意个字符、最后以数字结尾的字符串找出:</b>";
     22 echo "<pre>";
     23 print_r($preg_arr);                             //
输出匹配的元素
     24 echo "</pre>";
     25 ?>

【代码解析】代码从一个数组中找出一些元素,这些元素匹配以任意大写字母开头,中间含有任意个字符,最后以数字结尾。满足这样匹配的正则表达式可以是^[A-Z].*[0-9]$,因为这个表达式将要作为PERL兼容的正则表达式函数,因此需要在其前后加上界定符,如代码的第19行所示。所以,最终传入给函数preg_grep()的正则表达式参数是/^[A-Z].*[0-9]$/。

函数preg_grep()会根据传入的正则表达式匹配原数组中各单元的元素,将匹配正则表达式的元素值存入数组返回。代码21-8的执行结果如图21-8所示。

调用该函数时,如果可选的第3个参数的传入值为PREG_GREP_INVERT,那么该函数会将数组中不匹配模式的单元返回。例如将代码21-8的第19行改为如下代码。


$preg_arr = preg_grep("/^[A-Z].*[0-9]$/",$test_preg, PREG_GREP_INVERT);

然后将第21行的说明信息稍加修改,再执行代码21-8,就会看到如图21-9所示的结果。

图21-8 使用函数preg_grep()找出匹配模式的数组单元

图21-9 调用函数preg_grep()时传入参数PREG_GREP_INVERT

21.4.3 进行正则表达式匹配的函数

PERL兼容的正则表达式函数preg_match()用来完成对正则表达式的匹配,语法如下。


int preg_match (string $pattern, string $subject [, array $matches [, int $flag]])

该函数在参数字符串subject中搜索与参数$pattern给出的正则表达式相匹配的内容。该函数的第3个参数是可选参数,该参数是一个数组,如果提供了第3个参数$matches,则其会被搜索的结果所填充。$matches[0]包含与整个模式匹配的文本,$matches[1]将包含与第一个捕获的括号中的子模式所匹配的文本,以此类推。函数perg_match()还有第4个参数,也是可选的,对这个参数,这里不再详细叙述。

函数perg_match()返回对$pattern的匹配次数,该返回值要么是0次(没有匹配)或1次,因为函数preg_match()在第一次匹配之后将停止继续匹配。如果出错,函数preg_match()返回FALSE。代码21-9演示了该函数的用法。

代码21-9 使用PERL兼容正则表达式函数preg_match()进行正则表达式匹配21-9.php


     01 <?php
     02 $str_arr = array(
     03 "PHP 
是优秀的Web
脚本语言",
     04 "Perl
的文本处理功能很强大"
     05 );                                              //
定义字符串数组
     06 
     07 foreach($str_arr as $str)
     08 {
     09     //
模式界定符后面的修正符"i" 
表示匹配时不区分大小写字母
     10     if(preg_match("/php/i", $str))
     11     {
     12         echo "
在字符串' $str '
中找到对'php'
的匹配";
     13         echo "<br/>";
     14         echo "<br/>";
     15     }
     16     else
     17     {
     18         echo "
在字符串' $str '
中<b>
未</b>
找到对'php'
的匹配";
     19         echo "<br/>";
     20         echo "<br/>";
     21     }
     22 }
     23 ?>

【代码解析】代码中通过函数preg_match()使用正则表达式/php/i在两个给定的字符串中匹配字符串php。因为该模式是传给PERL兼容的正则表达式函数的参数,所以模式前后加上了//,称为/php/i。读者可能已经注意到,这里的模式最后加了一个字符i,这个字符就是21.4.1小节介绍的修正符,它的作用是匹配时不区分大小写字母。这段代码的执行结果如图21-10所示。

图21-10 使用正则表达式匹配函数preg_match()

21.4.4 进行全局正则表达式匹配的函数

和函数preg_match()极为类似的一个函数是preg_match_all(),该函数进行全局正则表达式匹配,语法如下。


int preg_match_all (string $pattern, string $subject, array $matches [, int $flag])

该函数在参数$subject中搜索所有与参数$pattern所给出的正则表达式匹配的内容,并将结果以参数$flag指定的顺序放到参数数组$matches中。该函数搜索到第一个匹配项之后,会继续进行匹配搜索,接下来的搜索从上一个匹配项末尾开始,这也是该函数preg_match()的一个区。该函数返回整个模式匹配的次数(可能为零),如果出错,返回FALSE。代码21-10演示了该函数的用法,演示了如何在字符串中搜索匹配的HTML标记。

代码21-10 全局正则表达式匹配函数preg_match_all()的应用21-10.php


     01 <?php
     02 $html = "<b>
粗体字符</b><a href=howdy.html>
可点击的连接</a>";//
定义一个复杂点的变量
     03 
     04 preg_match_all ("/(<([\w]+)[^>]*>)(.*)(<\/\\2>)/", $html, $matches);
                                                                                                                        //
进行全局正则表达式匹配
     05 
     06 for ($i=0; $i< count($matches[0]); $i++)
     07 {
     08     echo "
匹配:".$matches[0][$i]."\n";;
     09     echo "
第一部分:".$matches[1][$i]."\n";
     10     echo "
第二部分:".$matches[3][$i]."\n";
     11     echo "
第三部分:".$matches[4][$i]."\n\n";
     12 }
     13 ?>

【代码解析】代码中的\\2是一个逆向引用的例子,其在PCRE中的含义是必须匹配正则表达式本身中第2组括号内的内容,在代码21-10中就是([\w]+)。因为字符串在双引号中,所以需要多加一个反斜杠符号。通过浏览器查看该程序的执行结果,如图21-11所示。单从这个页面还看不出程序的执行结果,需要查看该页面的源代码,才能更清楚地了解程序的执行结果。在浏览器中查看该页面的源代码,如图21-12所示。

图21-11 在程序中使用函数preg_match_all()

图21-12 代码21-10执行结果的源代码形式

从这个源代码中可以更清楚地看到函数preg_match_all()是如何使用的以及该函数的执行结果。

21.4.5 执行正则表达式的搜索和替换的函数

函数preg_replace()可以完成对正则表达式的搜索和替换,语法如下。


mixed preg_replace ( mixed $pattern, mixed $replacement, mixed $subject [, int $limit])

该函数在参数$subject中搜索参数$pattern模式的匹配项,并替换为参数$replacement所指定的值。该函数的第4个参数是可选的,如果指定了参数$limit,那么该函数仅替换limit个匹配,如果省略参数$limit或者其值为-1,则所有的匹配项都会被替换。

如果函数preg_replace()搜索到匹配项,则会返回被替换后的$subject,否则返回原来不变的参数$subject。函数preg_replace()的每个参数(除了参数$limit)都可以是一个数组。如果参数$pattern和参数$replacement都是数组,那么该函数将以其键名在数组中出现的顺序来进行处理。这不一定和索引的数字顺序相同。所以,如果使用索引来标识哪个pattern将被哪个replacement来替换,应该在调用preg_replace()之前用函数ksort()对数组进行排序,如代码21-11所示。

代码21-11 使用正则表达式搜索和替换的函数preg_repalce()21-11.php


     01 <?php
     02 $string = "The quick brown fox jumped over the lazy dog.";
 //
定义字符串变量
     03 echo "
原字符串:<br/>";
     04 echo $string;
     05 echo "<br/><br/>";
     06 
     07 $patterns[0] = "/quick/";
     08 $patterns[1] = "/brown/";
     09 $patterns[2] = "/fox/";
     10 
     11 $replacements[2] = "bear";
     12 $replacements[1] = "black";
     13 $replacements[0] = "slow";
     14 
     15 $str1 = preg_replace($patterns, $replacements, $string);
 //
替换字符串
     16 echo "
使用函数ksort()
之前字符串替换为:<br/>";
     17 echo $str1;
     18 echo "<br/><br/>";
     19 
     20 ksort($patterns);                                       
 //
排序
     21 ksort($replacements);                                   
 //
排序
     22 
     23 $str2 = preg_replace($patterns, $replacements, $string);
     24 echo "
使用函数ksort()
之前字符串替换为:<br/>";
     25 echo $str2;
     26 echo "<br/><br/>";
     27 ?>

【代码解析】 程序定义了两个数组$patterns和$replacements。第20~21行分别对这两个数组进行排序。程序输出的是排序前和排序后的替换结果,如图21-13所示。

21.5.6 用正则表达式分割字符串的函数

和函数split()一样,兼容PERL正则表达式的函数preg_split()也可以通过一个正则表达式来完成对字符串的分割,语法如下。


array preg_split (string $pattern, string $subject [, int $limit [, int $flag]])

该函数返回一个数组,这个数组包含参数$subject中按与参数$pattern匹配的边界所分割的子串。如果指定了可选的第3个参数$limit,则最多返回limit个子串。如果limit是-1,则表示没有限制,可以用来继续指定可选参数$flag。该函数的第4个参数$flag是可选的,它有如下取值。

·PREG_SPLIT_NO_EMPTY:如果设定了本标记,则preg_split()只返回非空的部分。

·PREG_SPLIT_DELIM_CAPTURE:如果设定了本标记,界定符模式中的括号表达式也会被捕获并返回。

·PREG_SPLIT_OFFSET_CAPTURE:如果设定本标记,对每个出现的匹配结果也同时返回其附属的字符串偏移量。注意,这改变了返回的数组的值,使其中的每个单元也是一个数组,其中第1项为匹配字符串,第2项为它在$subject中的偏移量。

代码21-12演示了该函数的用法。

代码21-12 使用函数preg_split()通过正则表达式匹配的串分割字符串21-12.php


     01 <?php
     02 $str = 'PHP language programming in Web';                       //
定义字符串变量
     03 echo "<b>
原字符串:</b><br>";
     04 echo $str;
     05 echo "<br/><br/>";
     06 
     07 $chars = preg_split('//', $str, -1, PREG_SPLIT_OFFSET_CAPTURE); //
分割字符串
     08 echo "<b>
调用函数preg_split()
后:</b>";
     09 echo "<pre>";
     10 print_r($chars);
     11 ?>

【代码解析】第2行定义了一个字符串变量,然后第07行通过函数preg_split()对字符串进行分割,代码的执行结果如图21-14所示。

图21-13 在程序中使用函数preg_replace()做替换

图21-14 使用函数preg_split()分割字符串到数组

相关教程

共有条评论 网友评论

验证码: 看不清楚?