第六章 正则表达式
1 编写正则表达式
编写正则表达式首先要了解正则表达式的语法。正则表达式是由普通字符和元字符组成的,通过元字符和普通字符的不同组合,可以写出不同意义的正则表达式。
以下是几个简单的正则表达式的例子。
' [A-Za-z0-9] ':表示所有的大写字母、小写字母及0~9的数字。
' ^hello':表示以hello开始的字符串。
' world$':表示以world结尾的字符串。
'.at':表示以除“\n”外的任意单个字符开头并以“at”结尾的字符串,如“cat”、“nat”等。
'^[a-zA-Z] ':表示一个以字母开头的字符串。
'hi{2}':表示字母h后跟着两个i即hii。
' (go)+ ':表示至少含有一个“go”字符串的字符串,如“gogo”。
掌握了一些简单的正则表达式的写法,就可以进一步组合成更复杂的正则表达式。
例如,身份证号码一般由18位数字或17位数字后面加一个X或Y字母组成,要匹配身份证号码,表达式可以写为:
^[0-9]{17}([0-9]|X|Y)$
其中,1{17}表示以17个数字开头,([0-9]|X|Y)$表示以一个数字或字母X或Y结尾,组合起来就成为身份证号码的规则。
又如,要匹配E-mail地址的正则表达式可以写为:
^[a-zA-Z0-9\-]+@[a-zA-Z0-9\-]+\.[a-zA-Z0-9\-\.]+$
其中,子表达式’2+'表示至少由一个字母、数字、下画线、连字符开始的字符串,由于连字符“-”是特殊符号,所以必须使用“\”对其转义。符号@匹配E-mail地址中的@符号。
2 Per兼容的语法扩充
Perl兼容的正则表达式的模式类似于Perl中的语法,表达式必须包含在定界符中,除数字、字母、反斜线外的任何字符都可以作为定界符。例如,表达式’/^(?i)php[34]/'中的正斜线“/”就是定界符。另外,如果定界符要出现在表达式中需要使用转义符转义。
Perl兼容的正则表达式除支持表4.3列出的语法格式外,还可以通过转义字符“\”和一些特殊字母的组合实现某些特殊的语法。
3 正则表达式的应用
3.1 字符串匹配
字符串的匹配是正则表达式的主要应用之一。在PHP提供的正则表达式函数中,使用preg_match()函数进行字符串的匹配查找,语法格式如下:
int preg_match(string $pattern, string $subject [, array $matches [, int $flags[,int $offset]]])
说明:在 s u b j e c t 字 符 串 中 搜 索 与 subject字符串中搜索与 subject字符串中搜索与pattern给出的正则表达式相匹配的内容。preg_match()函数返回$pattern所匹配的次数。不是0次(没有匹配)就是1次,因为preg_match()函数在第一次匹配之后将停止搜索。例如:
<?php
$string="PHP is the web scripting language of choice.";
//模式定界符后面的 "i" 表示不区分大小写字母的搜索
$num=preg_match('/php/i', $string);
echo $num; //输出1
?>
函数如果提供了 m a t c h e s 参 数 , 则 其 会 被 搜 索 的 结 果 所 填 充 。 matches参数,则其会被搜索的结果所填充。 matches参数,则其会被搜索的结果所填充。matches[0]将包含与整个模式匹配的文本,$matches[1]将包含与第一个捕获的括号中的子模式所匹配的文本,以此类推。例如:
<?php
$string="http://www.php.net/index.html";
preg_match('/^(http:\/\/)?([^\/]+)/i', $string, $matches1); //从URL中取得主机名
echo $matches1[0]; //输出http://www.php.net
$host=$matches1[2];
echo $host; //输出www.php.net
preg_match('/[^\.\/]+\.[^\.\/]+$/', $host, $matches2); //从主机名中取得后面两段
echo "域名为:$matches2[0]"; //输出"域名为:php.net"
?>
PHP还有一个字符串匹配函数preg_match_all()。语法格式如下:
int preg_match_all(string $pattern, string $subject, [,array $matches [, int $flags[,int $offset]]])
说明:该函数的语法格式与preg_match()函数相同,作用也是搜索指定字符串并放到相应数组中。不同的是,preg_match()函数在搜索到第一个匹配结果时即停止匹配,而preg_match_all()函数搜索到第一个匹配结果后会从第一个匹配项的末尾开始继续搜索,直到搜索完整个字符串。preg_match_all()函数参数$flags的值可以取以下三种:
- PREG_PATTERN_ORDER。默认项,表示 m a t c h e s [ 0 ] 为 全 部 模 式 匹 配 的 数 组 , matches[0]为全部模式匹配的数组, matches[0]为全部模式匹配的数组,matches[1]为第一个括号中的子模式所匹配的字符串组成的数组,以此类推。
- PREG_SET_ORDER。如果设定此标记,则 m a t c h e s [ 0 ] 为 第 一 组 匹 配 项 的 数 组 , matches[0]为第一组匹配项的数组, matches[0]为第一组匹配项的数组,matches[1]为第二组匹配项的数组,以此类推。
- PREG_OFFSET_CAPTURE。PREG_OFFSET_CAPTURE可以和其他两个标记组合使用,如果设定本标记,对每个出现的匹配结果也同时返回其附属的字符串偏移量。
<?php
$html="<b>bold text</b><a href=howdy.html>click me</a>";
preg_match_all('/(<([\w]+)[^>]*>)(.*)(<\/\\2>)/', $html, $matches);
for ($i=0; $i< count($matches[0]); $i++)
{
echo "matched: ".htmlspecialchars($matches[0][$i])."<br/>";
echo "part 1: ".htmlspecialchars($matches[1][$i])."<br/>";
echo "part 2: ".htmlspecialchars($matches[3][$i])."<br/>";
echo "part 3: ".htmlspecialchars($matches[4][$i])."<br/>";
}
?>
3.2 字符串的替换
使用preg_replace()函数在字符串中查找匹配的子字符串,并用指定字符串替换子字符串。语法格式如下:
mixed preg_replace(mixed $pattern, mixed $replacement, mixed $subject [, int $limit[, int &$count]])
$replacement中可以包含如“\ n ” 或 “ n”或“ n”或“n”的逆向引用,$n取值为1~99,优先使用后者。替换模式在一个逆向引用后面紧接着一个数字(即紧接在一个匹配的模式后面的数字)时,不能使用“\$n”来表示逆向引用。例如,“\11”将会使preg_replace()函数无法分清是一个“\1”的逆向引用后面跟着一个数字1,还是一个“\11”的逆向引用。解决方法是使用“${1}1”。这会形成一个隔离的“$1”逆向引用,而另一个“1”只是单纯的字符。例如:
<?php
$str="<p>phpchina</p>";
echo preg_replace('/<(.*?)>/', "($1)",$str); //输出'(p)phpchina(/p)'
?>
在函数语法格式中,如果 s u b j e c t 是 一 个 数 组 , 则 会 对 subject是一个数组,则会对 subject是一个数组,则会对subject中的每个项目执行搜索和替换,并返回一个新数组。如果 p a t t e r n 和 pattern和 pattern和replacement都是数组,则preg_replace()函数会依次从 p a t t e r n 中 取 出 值 来 对 pattern中取出值来对 pattern中取出值来对subject进行搜索和替换。例如:
<?php
$array1=array("/a/", "/b/", "/c/");
$array2=array("d", "e", "f");
$str="abc";
$newstr=preg_replace($array1,$array2,$str); //将a、b、c分别替换为d、e、f
echo $newstr; //输出"def"
?>
3.3 字符串的分割
preg_split()函数可以使用正则表达式作为边界分割一个字符串,并将子字符串存入一个数组返回。语法格式如下:
array preg_split(string $pattern, string $subject [, int $limit [, int $flags ]])
说明:本函数区分大小写,返回一个数组,数组包含 s u b j e c t 中 沿 着 与 subject中沿着与 subject中沿着与pattern匹配的边界所分割的子串。 l i m i t 是 可 选 参 数 , 如 果 指 定 则 最 多 返 回 limit是可选参数,如果指定则最多返回 limit是可选参数,如果指定则最多返回limit个字串,如果省略则默认为-1,没有限制。$flags的值可以是以下三种。
- PREG_SPLIT_NO_EMPTY。如果设定本标记,则函数只返回非空的字符串。
- PREG_SPLIT_DELIM_CAPTURE。如果设定本标记,则定界符模式中的括号表达式的匹配项也会被捕获并返回。
- PREG_SPLIT_OFFSET_CAPTURE。如果设定本标记,则对每个出现的匹配结果也同时返回其附属的字符串偏移量。
例如:
<?php
$str="hi, i am a phper";
$keywords=preg_split("/[\s,]+/", $str); //以空白符或逗号作为定界符
print_r($keywords);
//输出Array ( [0] => hi [1] => i [2] => am [3] => a [4] => phper )
?>
3.4 返回匹配后的数组单元
使用preg_grep()函数可以根据条件查找指定的数组,并将符合条件的数组单元返回。语法格式如下:
array preg_grep(string $pattern, array $input [, int $flags ])
函数返回一个数组,数组包含 i n p u t 数 组 中 与 input数组中与 input数组中与pattern相匹配的数组单元。 f l a g s 是 可 选 参 数 , 值 可 以 是 P R E G G R E P I N V E R T , 表 示 返 回 输 入 数 组 中 不 匹 配 给 定 flags是可选参数,值可以是PREG_GREP_INVERT,表示返回输入数组中不匹配给定 flags是可选参数,值可以是PREGGREPINVERT,表示返回输入数组中不匹配给定pattern的单元。例如:
<?php
$array=array("name","number","project","input");
$newarray1=preg_grep("/^n/",$array); //匹配以字母"n"开头的单词
print_r($newarray1); //输出Array ( [0] => name [1] => number )
$newarray2=preg_grep("/e+/",$array); //匹配含有字母"e"的单词
print_r($newarray2); //输出Array ( [0] => name [1] => number [2] => project )
?>