PHP中的正则表达式
在php中,有两套正则表达式函数库,两者功能相似、知识执行效率略有差异:
PCRE
库提供,使用preg_
为前缀命名的函数POSIX
扩展提供的。使用以ereg_
为前缀命名的函数
PCRE
来源于Perl
语言,而Perl是对字符串操作功能最强大的语言之一,PHP
的最初版本就是由Perl
开发的产品。
PCRE
语法支持更多特性,比POSIX
语法更强大。
与Perl语言兼容的正则表达式处理函数
函数名 | 功能描述 |
---|---|
preg_match() | 进行正则表达式匹配 |
preg_match_all() | 进行全局正则表达式匹配 |
preg_replace() | 执行正则表达式的搜索和替换 |
preg_split() | 用正则表达式分割字符串 |
preg_grep() | 返回与模式匹配的数组单元 |
preg_replace_callback | 用回调函数执行正则表达式的搜索和替换 |
正则表达式语法规则
正则表达式作为一个匹配的模板,是由原子(普通字符,例如字符a到z)、特殊字符(元字符,例如*、+和?等)、以及模式修正符三部分组成的匹配模板。
定界符
在程序语言中,使用与Perl
兼容的正则表达式,通常都需要将模式表达式放入定界符之间,如/
。
作为定界符常使用反斜线/
,如/apple/
。用户只要把需要匹配的模式内容放入定界符之间即可。作为定界的字符也不仅仅局限于/
。除了字母、数字和斜线\
以外的任何字符都可以作为定界符,像 #
、|
、!
等都可以的。
1 | /<\/\w+>/ --使用反斜线作为定界符合法 |
原子
原子是正则表达式的最基本的组成单元,而且在每个模式中最少要少包含一个原子。原子是由所有那些未显示指定为元字符的打印和非打印字符组成,具体分为5类。
- 普通字符作为原子: 如
a~z
、A~Z
、0~9
等 - 一些特殊字符和转义后元字符作为原子:所有标点符号,但语句特殊意义的符号需要转义后才可作为原子,如:
\” \’ \* \+ \? \.
等 - 一些非打印字符作为原子: 如:
\f \n \r \t \v \cx
- 使用“通用字符类型”作为原子:如:
\d \D \w \W \s \S
。 - 自定义原子表
([])
作为原子:如:/[apj]sp/
、/[^apj]sp/
正则表达式中常用的非打印字符
原子字符 | 含义描述 |
---|---|
\cx | 匹配由x指明的控制字符。如\cM匹配一个Control-M或回车符。x的值必须为A |
\f | 匹配一个换页符。等价于 \x0c或\cL |
\n | 匹配一个换行符。等价于 \x0a或\cJ |
\r | 匹配一个回车符。等价于 \x0d或\cM |
\t | 匹配一个制表符。等价于 \x09或\cI |
\v | 匹配一个垂直制表符。等价于 \x0b或\cK |
正则表达式中常用的“通用字符类型”
原子字符 | 含义描述 |
---|---|
\d | 匹配任意一个十进制数字,等价于[0-9] |
\D | 匹配任意一个除十进制数字以外的字符,等价于[^0-9] |
\s | 匹配任意一个空白符,等价于[\f\n\r\t\v] |
\S | 匹配除空白符以外任何字符,等价于[^\f\n\r\t\v] |
\w | 匹配任意一个数字、字母或下画线,等价于[0-9a-zA-Z_] |
\W | 匹配一个除数字、字母或下画线以外的任意一个字符,等价于[^0-9a-zA-Z_] |
元字符
元字符 | 含义描述 |
---|---|
***** | 匹配0次、1次或多次其前的原子 |
+ | 匹配1次或多次其前的原子 |
? | 匹配0次或1次其前的原子 |
. | 匹配除了换行符外的任意一个字符 |
** | ** |
{n} | 表示其前面的原子恰好出现n次 |
{n,} | 表示其前面的原子出现不小于n次 |
{n,m} | 表示其前面的原子至少出现n次,最多出现m次 |
^或\A | 匹配输入字符串的开始位置(或在多行模式下行的开头,即紧随一个换行符之后) |
$或\Z | 匹配输入字符串的结束位置(或在多行模式下行的结尾,即紧随一个换行符之前) |
\b | 匹配单词的边界 |
\B | 匹配除单词边界以外的部分 |
[] | 匹配方括号中指定的任意一个原子 |
[^] | 匹配除方括号中的原子以外的任意一个字符 |
( ) | 匹配其整体为一个原子,即模式单元。可以理解为由多个单个原子组成的大原子 |
字符串边界限制
^
:指定字符串的开始&
:指定支付的结束1
2
3
4
5
6$check = '/^apple/'; //^匹配字符串开头为apple
$check = '/apple$/'; //$匹配字符串结尾为apple
$check = '/^apple$/'; //完全匹配字符串是apple
$check = '/apple/'; //模糊匹配字符串含有apple
preg_match($check, 'apple',$info);
var_dump($info); //输出array(1) { [0]=> string(5) "apple" }单词边界限制
在使用各种编辑软件的查找功能时,可以通过选择“按单词查找”获得更准确的结果。正则表达式中也提供类似的功能。
例如:在字符串“This island is a beautiful land”中
\b
:对单词的边界进行匹配\B
:对除单词边界以外的部分进行匹配1
2
3
4
5
6$check = '/\bis\b/'; //完全匹配单词is
$check = '/\bis/'; //匹配单词is开头的
$check = '/\Bis\B/'; //不与单词的左、右边界匹配,只匹配单词的内部。
$check = '/\Bis/'; //匹配非is开头的单词
preg_match_all($check, 'This island is a beautiful land',$info);
var_dump($info);重复匹配
正则表达式中有一些用于重复匹配某些原子的元字符:“?”、“*”、“+”。他们主要的区别是重复匹配的次数不同。
?
:表示0次或1次匹配紧接在其前的原子*
:表示0次、1次或多次匹配紧接在其前的原子+
:表示1次或多次匹配紧接在其前的原子1
2
3
4
5$check = '/Th?is/'; //匹配Tis,This
$check = '/Th*is/'; //匹配Tis,This,Thhis等
$check = '/Th+is/'; //匹配This,Thhis等
preg_match($check, 'This',$info);
var_dump($info);{}
:准确的指定原子重复的次数,指定匹配所匹配的原子出现的次数.
:匹配除换行符外任何一个字符通常可以使用“.*”组合来匹配除换行符外的任何字符。
1 | $check = '/^a.*z$/'; //匹配字母a开头,z结尾的任意不包含换行符的字符串 |
方括号表达式
[]
:存放一组原子,彼此地位平等,仅匹配其中的一个原子。例如想匹配一个a
或e
,使用[ae]
。- 例如:
Pr[ae]y
匹配Pray
或者Prey
。
- 例如:
[^]
:排除原子表,匹配除表内原子外的任意一个字符。- 例如:
/p[^u]/
匹配part
中的pa
,但无法匹配computer
中的pu
因为u
在匹配中被排除。
- 例如:
[-]
:用于连接一组按ASCII
码顺序排序的原子,简化书写。- 例如:
/x[0123456789]/
可以写成x[0-9]
,用来匹配一个由x
字母与一个数字组成的字符串。其他常用的匹配:
/[a-zA-Z]/匹配所有大小写字母
/^[a-z][0-9]$/匹配比如“z2”、 “t6” 、“g7”
/0[xX][0-9a-fA-F]/匹配一个简单的十六进制数字,如“0x9”。
/[^0-9a-zA-Z_]/匹配除英文字母、数字和下划线以外任何一个字符,其等价于\W。
/0?[ xX][0-9a-fA-F]+/匹配十六进制数字,可以匹配“0x9B3C”或者“X800”等。
/<[A-Za-z][A-Za-z0-9]*>/可以匹配“”、“
”或“”等HTML标签,并且不严格的控制大小写。
- 例如:
模式选择符
|
:在正则表达式中匹配两个或更多的选择之一()
:将其中的正则表达式变为原子(或称模式单元)使用,与数学表达式中的括号类似。- 例1:
/(Dog)+/
匹配的Dog
、DogDog
、DogDogDog
,因为紧接着+
前的原子是元字符()
括起来的字符串Dog
。 - 例2:
/Hello (world|earth)/
匹配Hello world
、Hello earth
。一个模式单元中的表达式将被优先匹配或运算。
- 例1:
重新使用的模式单元
系统自动将模式单元()
中的匹配依次存储起来,在需要时可以用\1
、\2
、\3
的形式进行引用。当正则表达式包含有相同的模式单元时,这种方法非常便于对其进行管理。注意使用时需要写成\\1
、\\2
- 例如:
/^\d{2}([\W])\d{2}\\1\d{4}$/
匹配12-31-2006
、09/27/1996
、86 01 4321
等字符串。但上述正则表达式不匹配12/34-5678
的格式。这是因为模式[\W]
的结果/
已经被存储。下个位置\1
引用时,其匹配模式也是字符/
。
当不需要存储匹配结果时使用非存储模式单元(?:)
- 例如:
/(?:a|b|c)(D|E|F)\\1g/
将匹配aEEg
。在一些正则表达式中,使用非存储模式单元是必要的。否则,需要改变其后引用的顺序。上例还可以写成/(a|b|c)(C|E|F)\\2g/
。模式匹配的优先级
顺序 | 元字符 | 描述 |
---|---|---|
1 | \ | 转义字符 |
2 | () (?:) (?=) [] | 模式单元和原子表 |
3 | *** + ? {n} {n,} {n,m}** | 重复匹配 |
4 | ^ $ \b \B \A \Z | 边界限制 |
5 | ** | ** |
模式修正符
修正符 | 含义描述 |
---|---|
i | 在和模式进行匹配时不区分大小写 |
m | 将字符串视为多行。默认的正则开始“^”和结束“$”将目标字符串作为单一的一“行”字符。加上m后,那么开始和结束将会指字符串的每一行。 |
s | 如果设定了此修正符,模式中的圆点元字符“.”匹配所有的字符,包括换行符。即将字符串视为单行,换行符作为普通字符看待 |
x | 模式中的空白忽略不计,除非它已经被转义 |
e | 只用在preg_replace()函数中,在替换字符串中对逆向引用做正常的替换,将其作为 PHP 代码求值,并用其结果来替换所搜索的字符串。 |
U | 本修正符反转了匹配数量的值使其不是默认的重复,而变成在后面跟上“?”才变得重复。这和 Perl 不兼容。也可以通过在模式之中设定 (U) 修正符或者在数量符之后跟一个问号(如启.*?)来用此选项。 |
D | 模式中的美元元字符仅匹配目标字符串的结尾。没有此选项时,如果最后一个字符是换行符的话,美元符号也会匹配此字符之前。如果设定了 m 修正符则忽略此选项 |
与Perl兼容的正则表达式函数
字符串的匹配和查找函数
preg_match()
:执行一个正则表达式匹配1
2
3
4
5
6
7
8
9
10
11
12
13
14
15// 一个用于匹配URL的正则表达式
$pattern = '/(https?|ftps?):\/\/(www)\.([^\.\/]+)\.(com|net|org)(\/[\w-\.\/\?\%\&\=]*)?/i';
//被搜索字符串
$subject = "网址为http://www.lampbrother.net/index.php的位置是LAMP兄弟连";
//使用preg_match()函数进行匹配
if(preg_match($pattern, $subject, $matches)) {
echo "搜索到的URL为:".$matches[0]."<br>"; //数组中第一个元素保存全部匹配结果
echo "URL中的协议为:".$matches[1]."<br>"; //数组中第二个元素保存第一个子表达式
echo "URL中的主机为:".$matches[2]."<br>"; //数组中第三个元素保存第二个子表达式
echo "URL中的域名为:".$matches[3]."<br>"; //数组中第四个元素保存第三个子表达式
echo "URL中的顶域为:".$matches[4]."<br>"; //数组中第五个元素保存第四个子表达式
echo "URL中的文件为:".$matches[5]."<br>"; //数组中第六个元素保存第五个子表达式
} else {
echo "搜索失败!"; //如果和正则表达式没有匹配成功则输出
}preg_match_all()
:执行全局正则表达式匹配1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21//声明一个可以匹配URL的正则表达式
$pattern = '/(https?|ftps?):\/\/(www|bbs)\.([^\.\/]+)\.(com|net|org)(\/[\w-\.\/\?\%\&\=]*)?/i';
// //声明一个包含多个URL链接地址的多行文字
$subject = "网址为http://bbs.lampbrother.net/index.php的位置是LAMP兄弟连,
网址为http://www.baidu.com/index.php的位置是百度,
网址为http://www.google.com/index.php的位置是谷歌。";
$i = 1; //定义一个计数器,用来统计搜索到的结果数
// //搜索全部的结果
if(preg_match_all($pattern, $subject, $matches, PREG_SET_ORDER)) {
foreach($matches as $urls) { //循环遍历二维数组$matches
echo "搜索到第".$i."个URL为:".$urls[0]."<br>";
echo "第".$i."个URL中的协议为:".$urls[1]."<br>";
echo "第".$i."个URL中的主机为:".$urls[2]."<br>";
echo "第".$i."个URL中的域名为:".$urls[3]."<br>";
echo "第".$i."个URL中的顶域为:".$urls[4]."<br>";
echo "第".$i."个URL中的文件为:".$urls[5]."<br>";
$i++; //计数器累加
}
} else {
echo "搜索失败!";
}preg_grep()
:返回匹配模式的数组条目1
2
3
4
5$array = array("Linux RedHat9.0", "Apache2.2.9", "MySQL5.0.51", "PHP5.2.6", "LAMP", "100");
//返回数组中以字母开始和以数字结束,并且没有空格的单元,赋给变量$version
$version = preg_grep("/^[a-zA-Z]+(\d|\.)+$/", $array);
print_r($version);
//输出:Array ( [1] => Apache2.2.9 [2] => MySQL5.0.51 [3] => PHP5.2.6 )其它字符串处理函数:
strstr()
、strpos()
、strrpos()
、substr()
字符串的替换函数1
2echo strstr("this is a test!", "test"); //输出test!
echo strstr("this is a test!", 115); //搜索 "s" 的ASCII值所代表的字符输出s is a test!字符串替换函数
preg_replace:执行一个正则表达式的搜索和替换
示例1:替换HTML标记
1
2
3
4
5
6
7
8
9
10
11
12
13//可以匹配所有HTML标记的开始和结束的正则表达式
$pattern = "/<[\/\!]*?[^<>]*?>/is";
//声明一个带有多个HTML标记的文本
$text = "这个文本中有<b>粗体</b>和<u>带有下画线</u>以及<i>斜体</i>
还有<font color='red' size='7'>带有颜色和字体大小</font>的标记";
echo $text;
echo "<br><br>";
//将所有HTML标记替换为空,即删除所有HTML标记
echo preg_replace($pattern, "", $text);
echo "<br><br>";
//通过第四个参数传入数字2,替换前两个HTML标记
echo preg_replace($pattern, "", $text, 2);示例2:替换日期格式
1
2
3
4$pattern = "/(\d{2})\/(\d{2})\/(\d{4})/"; //日期格式的正则表达式
$text="今年国庆节放假日期为10/01/2012到10/07/2012共7天。"; //带有两个日期格式的字串
echo preg_replace($pattern, "\\3-\\1-\\2", $text); //将日期替换为以“-”分隔的格式
echo preg_replace($pattern, "\${3}-\${1}-\${2}",$text); //将“\\1”改为“\${1}”的形式str_replace : 子字符串替换
该函数返回一个字符串或者数组。通过
$count
参数指定来获取替换的次数。示例1:
1
2
3
4
5
6
7
8//声明包含多个“LAMP”字符串的文本,也包含小写的“lamp”字符串
$str="LAMP是目前最流行的WEB开发平台;<br>LAMP为B/S架构软件开发的黄金组合;<br>LAMP每个成员都是开源软件;<br>lampBrother是LAMP的技术社区。<br>";
//区分大小写的将“LAMP”替换为“Linux+Apache+MySQL+PHP”,并统计替换次数
echo str_replace("LAMP", "Linux+Apache+MySQL+PHP",$str, $count);
echo "区分大小写时共替换".$count."次<br>"; //替换4次
//不区分大小写的将“LAMP”替换为“Linux+Apache+MySQL+PHP”,并统计替换次数
echo str_ireplace("LAMP", "Linux+Apache+MySQL+PHP", $str,$count);
echo "不区分大小写时共替换".$count."次<br>"; //替换5次示例2:
1
2
3
4
5
6
7
8//元音字符数组
$vowels = array("a", "e", "i", "o", "u", "A", "E", "I", "O", "U");
//将第三个参数中的字符串,搜索到的数组中的元素值都被替换为空,区分大写小替换
echo str_replace($vowels, "", "Hello World of PHP"); //输出: Hll Wrld f PHP
//元音字符数组
$vowels = array("a", "e", "i", "o", "u");
//将第三个参数中的字符串,搜索到的数组中的元素值都被替换为空,不区分大写小替换
echo str_ireplace($vowels, "", "HELLO WORLD OF PHP"); //输出:HLL WRLD F PHP字符串的分割与连接
preg_split:通过一个正则表达式分隔字符串
PREG_SPLIT_NO_EMPTY
:返回分隔后的非空部分PREG_SPLIT_DELIM_CAPTURE
:用于分隔的模式中的括号表达式将被捕获并返回.PREG_SPLIT_OFFSET_CAPTURE
:返回附加字符串偏移量1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18//按任意数量的空格和逗号分隔字符串,其中包含" ", \r, \t, \n and \f
$keywords = preg_split ("/[\s,]+/", "hypertext language, programming");
print_r($keywords);
//分割后输出Array ( [0] => hypertext [1] => language [2] => programming )
//将字符串分割成字符
$chars = preg_split('//', "lamp", -1, PREG_SPLIT_NO_EMPTY);
print_r($chars); //分割后输出Array ( [0] => l [1] => a [2] => m [3] => p )
//将字符串分割为匹配项及其偏移量
$chars = preg_split('/ /','hypertext language programming', -1,
PREG_SPLIT_OFFSET_CAPTURE);
print_r($chars);
/* 分割后输出:
Array ( [0] => Array ( [0] => hypertext [1] => 0 )
[1] => Array ( [0] => language [1] => 10 )
[2] => Array ( [0] => programming [1] => 19 ) ) */explode:使用一个字符串分割另一个字符串
array explode(string $separator,string $string[,int $limit])
此函数返回由字符串组成的数组,每个元素都是string
的一个子串,它们被字符串separator
作为边界点分割出来。 其中$limit
是指定对大分割个数。1
2
3
4
5
6
7
8
9
10
11
12
13$lamp = "Linux Apache MySQL PHP"; //声明一个字符串$lamp,每个单词之间使用空格分割
$lampbrother = explode(" ", $lamp); //将字符串$lamp使用空格分割,并组成数组返回
$password = "redhat:*:500:508::/home/redhat:/bin/bash"; //将Linux中的用户文件的一行提出
//按“:”分割7个子串,并存放对对应的变量中.
list($user, $pass, $uid, $gid, , $home, $shell) = explode(":", $password);
//声明字符串$lamp,每个单词之间使用加号“+”分割
$lamp = "Linux+Apache+MySQL+PHP";
//使用正数限制子串个数,而最后那个元素将包含 $lamp中 的剩余部分
print_r(explode('+', $lamp, 2)); //输出Array ( [0] => Linux [1] => Apache+MySQL+PHP )
//使用负数限制子串,则返回除了最后的限制个元素外的所有元素
print_r(explode('+', $lamp, -1)); //输出Array ( [0] => Linux [1] => Apache [2] => MySQL )implode:使用一个子串组装一个数组。
string implode(string $glue,array $pieces)
将pieces
数组中的每个值,使用glue
作为分隔符组装成一个子串并返回。1
2
3$lamp = array("Linux", "Apache", "MySQL", "PHP");
echo implode("+", $lamp); //使用加号连接后输出Linux+Apache+MySQL+PHP
echo join("+++", $lamp); //使用三个加号连接后输出Linux+++Apache+++MySQL+++PHP