PHP支持两种风格的正则表达式语法:POSIX和Perl。POSIX风格的正则表达式更容易掌握,但不能安全用于二进制模式,而Perl兼容的正则表达式相对比较复杂。
正则表达式就是有普通字符(如a~z)和特殊字符(称为元字符)组成的字符串模式。使用正则表达式可以完成以下功能:①测试字符串的某个模式;②替换文本;③根据模式匹配从字符串中提取一个子字符串。
一、POSIX风格的正则表达式
1.编写正则表达式
正则表达式是有普通字符和元字符组成的,通过元字符和普通字符的不同组合,可以写出不同意义的正则表达式。
POSIX正则表达式语法格式列表
字符 | 描述 |
\ | 转义字符,用于转义特殊字符。 |
^ | 匹配输入字符串的开始位置。 |
$ | 匹配输入字符串的结束位置。 |
* | 匹配前面的子表达式零次或多次。 |
+ | 匹配前面的子表达式一次或多次。 |
? | 匹配前面的子表达式零次或一次。 |
{n} | n是一个非负整数,匹配确定的n次。 |
{n,} | n是一个非负整数,至少匹配n次。 |
{n,m} | m和n均是非负整数,其中n<=m,最少匹配n次且最多匹配m次。注意在逗号和两个数之间不能有空格。 |
? | 当该字符紧跟在任何一个其他限制符(*,+,?,{n},{n,},{n,m})后面时,匹配模式是非贪婪的。非贪婪模式尽可能少地匹配所搜索的字符串,而默认的贪婪模式则尽可能多地匹配所搜索的字符串。 |
. | 匹配除"\n"之外的任何单个字符,要匹配包括‘\n‘在内的任何字符,可以使用‘[.\n]‘的模式。 |
(pattern) | 匹配pattern并获取这一匹配。所获取的匹配保存到相应的数组中。要匹配圆括号字符,请使用‘\(‘或‘\)‘。 |
(?:pattern) | 匹配pattern但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储。这在使用‘‘或"|"来组合一个模式的各个部分时很有用。 |
(?=pattern) | 正向预查,在任何匹配pattern的字符串开始出匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。预查不消耗字符,也就是说,在一个匹配发生后,在会后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。 |
(?!pattern) | 负向预查,在任何不匹配pattern的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说该匹配不需要获取供以后使用。预查不消耗字符,也就是说,在一个匹配发生后,在会后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。 |
x|y | 匹配x或y。 |
[xyz] | 字符集合。匹配所包含的任意一个字符。 |
[^xyz] | 负值匹配字符集。匹配未包含的任意字符。 |
[a-z] | 字符范围。匹配制定范围内的任意字符。 |
[^a-z] | 负值字符范围。匹配不在指定范围内的任意字符。 |
注意:在PHP中最好将正则表达式放在单引号中。
2.字符串的匹配
在PHP中,用于匹配POSIX风格正则表达式的函数有ereg()和eregi()函数。
使用ereg()函数可以查找字符串与子字符串匹配的情况,并返回匹配字符串的长度,还可以借助参数返回匹配字符的数组。语法:
int ereg(string ($pattern), string $string[, array $reg])
ereg()函数在字符串$string中查找与给定正则表达式$pattern相匹配的子字符串。$pattern中可以使用圆括号“()”将一些子模式括起来获取这一匹配。如果找到与$pattern圆括号内的子模式相匹配的子串并且函数调用了第三个参数$regs,则匹配项将被存入$regs数组中。$regs[1]包含第一个左圆括号开始的紫川,$regs[2]包含第二个子串,以此类推。$regs[0]好汉整个匹配的字符串。如果在$string中找到$pattern模式的匹配,则返回所匹配字符串的长度,如果没有找到匹配或出错则返回FALSE。如果没有传入可选参数$regs或者所匹配的字符串长度为0,则本函数返回1.
eregi()函数功能与ereg()函数基本相同,不过ereg()函数区分大小写,eregi()函数不区分大小写。
3.字符串的替换
POSIX风格的正则表达式函数ereg_replace()函数与str_replace()函数一样,可以将查到的字符串替换为指定字符串。而ereg_replace()函数能实现更为复杂的字符串操作。ereg_replace()函数语法格式:
string ereg_replace(string $pattern,string $replacement,string $string)
函数使用字符串$replacement替换字符串$string中的$pattern匹配的部分,并返回替换后的字符串。若未找到匹配项,则原样返回。
如果$pattern包含有括号的子集,则$replacement可以包含形如“\\$num”的子串,$num表示一个数字,这些子串将被替换为正则表达式中的$num个括号内的子串,这种用法成为逆向引用。
eregi_replacement()函数不区分大小写。
4.分割数组
使用split()函数可以完成与explode()函数一样的功能,而且可以根据给出的正则表达式来分割字符串,并返回一个数组。
array split(string $pattern,string $string[,int $limit])
本函数使用$pattern作为边界对字符串$string进行分割,并将分割后的子字符串保存在数组中返回。如果设定了$limit,则返回的数组最多包含$limit个单元,而其中最后一个单元包含了$string中生育的所有部分。
spliti()函数不区分大小写。
5.产生正则表达式
使用sql_regcase()函数可以产生不区分大小写的正则表达式。
string sql_regcase(string $string)
函数返回与$string相匹配的正则表达式,不区分大小写字母。返回的表达式是将$string中的每个字母字符转换为方括号表达式,该方括号表达式包含了该子母的大小写形式。其他字符保留不变。
二、Perl兼容的正则表达式
1.编写正则表达式
Perl兼容的正则表达式必须包含在定界符中,除数字、字幕、反斜线外的任何字符后可以作为定界符,另外,如果定界符要出现在表达式中需要使用转义符转义。
Perl兼容的正则表达式扩充的语法格式
字符 | 描述 |
\b |
匹配一个单词边界,也就是指单词和空格间的位置。 |
\B | 匹配非单词边界。 |
\cx | 匹配由x指明的控制字符。x的值必须为A~Z或a~z之一。否则,将‘c’是为一个原义的‘c’字符 |
\d | 匹配一个数字字符。 |
\D | 匹配一个非数字字符。 |
\f | 匹配一个换页符。 |
\n | 匹配一个换行符。 |
\r | 匹配一个回车符。 |
\s | 匹配任何空白字符,包括空格、制表符、换页符等。 |
\S | 匹配任何非空白字符。 |
\t | 匹配一个制表符 |
\v | 匹配一个垂直制表符 |
\w | 匹配包括下划线的任何单词字符。 |
\W | 匹配任何飞单词字符。等价于[^A-Za-z0-9] |
\xn | 匹配n,其中n为十六进制转义值。十六进制转义值必须为确定的两个数字长。正则表达式中可以使用ASCII码 |
\num | 匹配num,其中num是一个正整数。对所获取的匹配的引用。 |
\n | 标志一个八进制转义值或一个后向引用。如果\n之前至少有n个获取得子表达式,则n为后向引用。否则,如果n为八进制数字(0~7),则n为一个八进制转义值。 |
\nm | 标志一个八进制转义值或一个后向引用。如果\nm之前至少有nm个获取得子表达式,则nm为后向引用。如果\nm之前至少有n个获取,则n为一个后跟文字m的后向引用。如果前面的田间都不满足,若n和m均为八进制数字(0-7),则\nm将匹配八进制转义值nm |
\nml | 如果n为八进制数字(0-3),且m和l均为八进制数字(0-7),则匹配八进制转义值nml |
\un | 匹配n,其中n是用4个十六进制数字表示的Unicode字符。 |
2.字符串匹配
使用preg_match()函数进行字符串的查找。语法格式如下:
int preg_match(string $pattern,string $subject[,array $matchs[,int $flags]])
在$subject字符串中搜索与$pattern给出的正则表达式相匹配的内容。preg_match()函数返回$pattern所匹配的次数。不是0次就是1次,因为preg_match()函数在第一次匹配之后将停止搜索。
函数如果提供了$matchs参数,则其会被搜索的结果所填充。$matchs[0]将包含与整个模式匹配的文本,$matchs[1]将包含与第一个捕获的括号中的子模式所匹配的文本,以此类推。
preg_relpace()函数语法格式中$flags是可选参数,值可以是PREG_OFFSET_CAPTURE。如果设定本标记,对每个出现的匹配结果也同时返回其附属的字符串偏移量。这改变了返回的数组的值,使其中的每个单元也是一个数组,其中第一项为匹配字符串,第二项为偏移量。
Perl兼容的正则表达式还有一个字符串匹配函数preg_match_all()。
int preg_match_all(string $pattern, string $subject,array $matchs[,int $flags])
该函数的语法格式与preg_match()函数相同,作用也是搜索指定字符串并放到相应数组中。不同的是,preg_match()函数在搜索到第一个匹配结果时就停止匹配,而preg_match_all()函数搜索到第一个匹配结果后会从第一个匹配项的末尾开始继续搜索,知道搜索完整个字符串。preg_match_all()函数单数$flags的值可以取以下三种:
ⅠPREG_PATTERN_ORDER.默认项,表示$matchs[0]为全部模式匹配的数组,$match[1]为第一个括号中的子模式所匹配的字符串组成的数组,以此类推。
ⅡPREG_SET_ORDER.如果设定此标记,则$matches[0]为第一组匹配项的数组,$matchs[1]为第二组匹配项的数组,以此类推。
ⅢPREG_OFFSET_CAPTURE.此标记可以和其他两个标记组合使用,如果设定本标记,对每个出现的匹配结果也同时返回其附属的字符串偏移量。
3.字符串替换
使用preg_replace()函数可以在字符串中查找匹配的子字符串,并用指定字符串替换子字符串。
mixed preg_replace(mixed $pattern, mixed $replacement,mixed $subject[,int $limit])
在$subject中搜索$pattern模式的匹配项并替换为$replacement。如果制定了$limit,则仅替换$limit个匹配项,如果省略$limit或者其值为-1,则所有的匹配项都会被替换。
函数语法格式中,如果$subject是个数组,则会对$subject中的每个项目执行搜索和替换,并返回一个新数组。如果$pattern和$replacement都是数组,则$preg_replace()函数会依次从$pattern中取出值来对$subject进行搜索和替换。
4.字符串分割
preg_split()函数可以使用正则表达式作为边界分割一个字符串,并将字符串存入一个数组返回,作用于split()函数类似。
array preg_split(string $pattern ,string $subject[,int $limit[,int $length]])
本函数区分大小写,返回一个数组,数组包含一个$subject中沿着与$pattern匹配的边界所分割的子串。$limit是可选参数,如果指定则最多返回$limit个字串,如果省略或为-1,则没有限制。$flags的值可以是以下三种:
ⅠPREG_SPLIT_NO_EMPTY.如果设定本标记,则函数只返回非空的字符串。
ⅡPREG_SPLIT_DELIM_CAPTURE,如果设定本标记,定界符模式的括号表达式的匹配项也会被捕获并返回。
ⅢPREG_SPLIT_OFFSET_CAPTURE.如果设定本标记,对每个出现的匹配结果也同时返回其附属的字符串偏移量。
5.返回匹配的数组单元
使用preg_grep()函数可以根据条件查找指定的数组,并将符合条件的数组单元返回。
array preg_grep(string $pattern,array $input[,int $flags])
函数返回一个数组,数组包含$input数组中与$pattern相匹配的数组单元。$flags是可选参数,值可以是PREG_GREP_INVERT,表示返回输入数组中不匹配给定$pattern的单元。
preg_grep()函数返回的数组使用原来数组的键名进行索引。
总结:在实际应用中,普通的字符串函数比正则表达式函数运行速度要快得多。在处理简单的字符串时,最好使用字符串函数来完成。在处理一些复杂的字符串时,当字符串函数不能解决问题,可以选择正则表达式函数来完成。如果要使用正则表达式函数,推荐使用Perl兼容的正则表达式函数。