正则表达式简介
|
元字符 | 说明 |
---|---|
. | 匹配除换行符意外的任意字符 |
w | 匹配字母或数字或下划线 |
s | 匹配任意的空白符 |
d | 匹配数字 |
b | 匹配单词的开始或结束 |
^ | 匹配字符串的开始 |
$ | 匹配字符串的结束 |
[x] | 匹配x字符,如匹配字符串中的 a、b 和 c 字符 |
W | w的反义,即匹配任意非字母,数字,下划线和汉字的字符 |
S | s的反义,即匹配任意非空白符的字符 |
D | d的反义,即匹配任意非数字的字符 |
B | b的反义,即不是单词开头或结束的位置 |
[^x] | 匹配除了 x 意外的任意字符,如 [^abc] 匹配除了 abc 这几个字母之外的任意字符 |
提示
- 当我们要匹配这些元字符的时候,我们需要用到字符转义功能,同样正则表达式里面用 来表示转义,如要匹配 . 符号,则需要用 . ,否则 . 会被解释成“除换行符外的任意字符”。当然,要匹配 ,则需要写成
- 连续的数字或字母可以用 – 符号连接起来,如匹配所有的小写字母,[1-5] 匹配 1 至 5 这 5 个数字
重复
正则表达式的威力在于其能够在模式中包含选择和循环,正则表达式用一些重复规则来表达循环匹配。
常用的重复如下:
重复 | 说明 |
---|---|
* | 重复零次或更多次 |
+ | 重复 1 次或更多次 |
? | 重复零次或 1 次 |
{n} | 重复 n 次 |
{n,} | 重复 n 次或更多次 |
重复 n 到 m 次 |
分枝
分枝是指制定几个规则,如果满足任意一种规则,则都当作匹配成功。具体来说就是用 | 符号把各种规则分开,且条件从左至右匹配。
提示
由于分枝规定,只要匹配成功,就不再对后面的条件加以匹配,所以如果你想匹配有包含关系的内容,请注意规则的顺序。
下面是一个使用分枝的例子。
美国的邮政编码的规则是 5 个数字或者 5 个数字连上 4 个数字,如 12345 或者 54321-1234 ,如果要匹配所有的邮编,则正确的正则表达式为:
d{5}-d{4}|d{5} //错误写法 d{5}|d{5}-d{4}
下面的错误写法,只能匹配到 5 位数字及 9 位数字的前 5 位数字的情况,而不能匹配 9 位数字的邮编。
分组
在正则表达式中,可以用小括号将一些规则括起来当作分组,分组可以作为一个元字符来看待。
分组的例子,验证 IP 地址:
(d{1,3}.){3}d{1,3}
这是一个简单的且不完善的匹配 IP 地址的正则表达式,因为它除了能匹配正确的 IP 地址外,还能匹配如 322.197.578.888 这种不存在的 IP 地址。
当然,用这个表达式简单匹配成功后可以在利用 PHP 的算术比较再加以判断 IP 地址是否正确。而正则表达式中没有提供算术比较功能,如果要完全匹配正确的 IP 地址,则需要改进如下:
((25[0-5]|2[0-4]d|[01]?dd?).){3}(25[0-5]|2[0-4]d|[01]?dd?)
规则说明
该规则关键之处在于确定 IP 地址每一段范围为 0-255 ,然后再重复 4 次即可。在:
25[0-5]|2[0-4]d|[01]?dd?
中,用分枝首先确定了 250-255 和 200-249 。 [01]?dd? 则确定了 0-199 的范围,综合起来就是 0-255 。
贪婪与懒惰
正则表达式默认的情况下,会在满足匹配条件下尽可能的匹配更多内容。如 a.*b,用他来匹配 aabab ,它会匹配整个 aabab ,而不会只匹配到 aab 为止,这就是贪婪匹配。
与贪婪匹配对应的是,在满足匹配条件的情况下尽可能的匹配更少的内容,这就是懒惰匹配。
上述例子对应的懒惰匹配规则为:
a.*?b
如果用该表达式去匹配 aabab ,那么就会得到 aab 和 ab 这样两个匹配结果。
常用的懒惰限定符如下:
*? | 重复任意次,但尽可能少重复 |
---|---|
+? | 重复 1 次或更多次,但尽可能少重复 |
?? | 重复 0 次或 1 次,但尽可能少重复 |
重复 n 次以上,但尽可能少重复 | |
重复 n 到 m 次,但尽可能少重复 |
模式修正符
模式修正符是标记在整个正则表达式之外的,可以看着是对正则表达式的一些补充说明。
常用的模式修正符如下:
i | 模式中的字符将同时匹配大小写字母 |
---|---|
m | 字符串视为多行 |
s | 将字符串视为单行,换行符作为普通字符 |
x | 将模式中的空白忽略 |
e | preg_replace() 函数在替换字符串中对逆向引用作正常的替换,将其作为 PHP 代码求值,并用其结果来替换所搜索的字符串。 |
A | 强制仅从目标字符串的开头开始匹配 |
D | 模式中的 $ 元字符仅匹配目标字符串的结尾 |
U | 匹配最近的字符串 |
u | 模式字符串被当成 UTF-8 |
正则表达式在 PHP 中的应用
在 PHP 应用中,正则表达式主要用于:
- 正则匹配:根据正则表达式匹配相应的内容
- 正则替换:根据正则表达式匹配内容并替换
- 正则分割:根据正则表达式分割字符串
在 PHP 中有两类正则表达式函数,一类是 Perl 兼容正则表达式函数,一类是 POSIX 扩展正则表达式函数。二者差别不大,而且推荐使用Perl 兼容正则表达式函数,因此下文都是以 Perl 兼容正则表达式函数为例子说明。
定界符
Perl 兼容模式的正则表达式函数,其正则表达式需要写在定界符中。任何不是字母、数字或反斜线()的字符都可以作为定界符,通常我们使用 / 作为定界符。具体使用见下面的例子。
尽管正则表达式功能非常强大,但如果用普通字符串处理函数能完成的,就尽量不要用正则表达式函数,因为正则表达式效率会低得多。关于普通字符串处理函数,请参见《PHP 字符串处理》。
preg_match()
preg_match() 函数用于进行正则表达式匹配,成功返回 1 ,否则返回 0 。
语法:
int preg_match( string pattern,string subject [,array matches ] )
参数 | pattern | 正则表达式 |
---|---|---|
subject | 需要匹配检索的对象 | |
matches | 可选,存储匹配结果的数组, $matches[0] 将包含与整个模式匹配的文本,$matches[1] 将包含与第一个捕获的括号中的子模式所匹配的文本,以此类推 |
例子 1 :
<?php if(preg_match("/php/i","PHP is the web scripting language of choice.",$matches)){ print "A match was found:". $matches[0]; } else { print "A match was not found."; } ?>
浏览器输出:
A match was found: PHP
在该例子中,由于使用了 i 修正符,因此会不区分大小写去文本中匹配 php 。
preg_match() 第一次匹配成功后就会停止匹配,如果要实现全部结果的匹配,即搜索到subject结尾处,则需使用 preg_match_all() 函数。
例子 2 ,从一个 URL 中取得主机域名 :
<?php // 从 URL 中取得主机名 preg_match("/^(http://)?([^/]+)/i","http://www.5idev.com/index.html",$matches); $host = $matches[2]; // 从主机名中取得后面两段 preg_match("/[^./]+.[^./]+$/",$host,$matches); echo "域名为:{$matches[0]}"; ?>
域名为:5idev.com
preg_match_all()
preg_match_all() 函数用于进行正则表达式全局匹配,成功返回整个模式匹配的次数(可能为零),如果出错返回 FALSE 。
int preg_match_all( string pattern,string subject,array matches [,int flags ] )
flags | 可选,指定匹配结果放入 matches 中的顺序,可供选择的标记有:
|
下面的例子演示了将文本中所有 <pre></pre> 标签内的关键字(php)显示为红色。
<?php $str = "<pre>学习php是一件快乐的事。</pre><pre>所有的phper需要共同努力!</pre>"; $kw = "php"; preg_match_all('/<pre>([sS]*?)</pre>/',$str,$mat); for($i=0;$i<count($mat[0]);$i++){ $mat[0][$i] = $mat[1][$i]; $mat[0][$i] = str_replace($kw,'<span style="color:#ff0000">'.$kw.'</span>',$mat[0][$i]); $str = str_replace($mat[1][$i],$mat[0][$i],$str); } echo $str; ?>
正则匹配中文汉字
正则匹配中文汉字根据页面编码不同而略有区别:
- GBK/GB2312编码:[x80-xff]+ 或 [xa1-xff]+
- UTF-8编码:[x{4e00}-x{9fa5}]+/u
例子:
<?php $str = "学习php是一件快乐的事。"; preg_match_all("/[x80-xff]+/",$match); //UTF-8 使用: //preg_match_all("/[x{4e00}-x{9fa5}]+/u",$match); print_r($match); ?>
输出:
Array ( [0] => Array ( [0] => 学习 [1] => 是一件快乐的事。 ) )
正则替换
preg_replace() 函数用于正则表达式的搜索和替换。
mixed preg_replace( mixed pattern,mixed replacement,mixed subject [,int limit ] )
替换的内容 | |
需要匹配替换的对象 | |
limit | 可选,指定替换的个数,如果省略 limit 或者其值为 -1,则所有的匹配项都会被替换 |
补充说明
- replacement 可以包含 n 形式或 $n 形式的逆向引用,首选使用后者。每个此种引用将被替换为与第 n 个被捕获的括号内的子模式所匹配的文本。n 可以从 0 到 99,其中 或 $0 指的是被整个模式所匹配的文本。对左圆括号从左到右计数(从 1 开始)以取得子模式的数目。
- 对替换模式在一个逆向引用后面紧接着一个数字时(如 11),不能使用 符号来表示逆向引用。因为这样将会使 preg_replace() 搞不清楚是想要一个 1 的逆向引用后面跟着一个数字 1 还是一个 11 的逆向引用。解决方法是使用 ${1}1。这会形成一个隔离的 $1 逆向引用,而使另一个 1 只是单纯的文字。
- 上述参数除 limit 外都可以是一个数组。如果 pattern 和 replacement 都是数组,将以其键名在数组中出现的顺序来进行处理,这不一定和索引的数字顺序相同。如果使用索引来标识哪个 pattern 将被哪个 replacement 来替换,应该在调用 preg_replace() 之前用 ksort() 函数对数组进行排序。
<?php $str = "The quick brown fox jumped over the lazy dog."; $str = preg_replace('/s/','-',$str); echo $str; ?>
输出结果为:
The-quick-brown-fox-jumped-over-the-lazy-dog.
例子 2 ,使用数组:
<?php $str = "The quick brown fox jumped over the lazy dog."; $patterns[0] = "/quick/"; $patterns[1] = "/brown/"; $patterns[2] = "/fox/"; $replacements[2] = "bear"; $replacements[1] = "black"; $replacements[0] = "slow"; print preg_replace($patterns,$replacements,$str); /*输出: The bear black slow jumped over the lazy dog. */ ksort($replacements); print preg_replace($patterns,$str); /*输出: The slow black bear jumped over the lazy dog. */ ?>
例子 3 ,使用逆向引用:
<?php $str = '<a href="http://www.5idev.com/">5idev</a>其他字符<a href="http://www.sohu.com/">sohu</a>'; $pattern = "/<as([sS]*?)>([sS]*?)</a>/i"; print preg_replace($pattern,'2',$str); ?>
5idev其他字符sohu
该例子演示了将文本中所有的 <a></a> 标签去掉。
preg_split()
preg_ split() 函数用于正则表达式分割字符串。
array preg_split( string pattern,int limit [,int flags]] )
返回一个数组,包含 subject 中沿着与 pattern 匹配的边界所分割的子串。
可选,如果指定了 limit ,则最多返回 limit 个子串,如果 limit 是 -1,则意味着没有限制,可以用来继续指定可选参数 flags |
设定 limit 为 -1 后可选,可以是下列标记的任意组合(用按位或运算符 | 组合):
|
<?php $str = "php mysql,apache ajax"; $keywords = preg_split("/[s,]+/",$str); print_r($keywords); ?>
Array ( [0] => php [1] => mysql [2] => apache [3] => ajax )
例子 2 :
<?php $str = 'string'; $chars = preg_split('//',-1,PREG_SPLIT_NO_EMPTY); print_r($chars); ?>
( [0] => s [1] => t [2] => r [3] => i [4] => n [5] => g )
例子 3 :
Array ( [0] => Array ( [0] => php [1] => 0 ) [1] => Array ( [0] => mysql [1] => 4 ) [2] => Array ( [0] => apache [1] => 10 ) [3] => Array ( [0] => ajax [1] => 17 ) )
split()
split() 函数同 preg_split() 类似,用正则表达式将字符串分割到数组中,返回一个数组,但推荐使用 preg_split() 。
array split( string pattern,string string [,int limit] )
如果设定了 limit ,则返回的数组最多包含 limit 个单元,而其中最后一个单元包含了 string 中剩余的所有部分。如果出错,则返回 FALSE。
<?php $date = "2008-08-08 20:00:01"; print_r( split('[- :]',$date) ); ?>
输出结果:
Array ( [0] => 2008 [1] => 08 [2] => 08 [3] => 20 [4] => 00 [5] => 01 )
提示
- 如果不需要正则表达式的功能,可以选择使用更快(也更简单)的替代函数如explode()或str_split()。
- split() 函数对大小写敏感,如果在匹配字母字符时忽略大小写的区别,请使用用法相同的 spliti() 函数
本文整理了常用的正则表达式以供参考,尽管以下正则表达式已经一一经过验证,但难免有所纰漏,大家在使用时还需要仔细验证。
表单验证匹配
验证账号,字母开头,允许 5-16 字节,允许字母数字下划线:^[a-zA-Z][a-zA-Z0-9_]{4,15}$
验证账号,不能为空,不能有空格,只能是英文字母:^S+[a-z A-Z]$
验证账号,不能有空格,不能非数字:^d+$
验证用户密码,以字母开头,长度在 6-18 之间:^[a-zA-Z]w{5,17}$
验证是否含有 ^%&',;=?$ 等字符:[^%&',;=?$x22]+
匹配Email地址:w+([-+.]w+)*@w+([-.]w+)*.w+([-.]w+)*
匹配腾讯QQ号:[1-9][0-9]{4,}
匹配日期,只能是 2004-10-22 格式:^d{4}-d{1,2}-d{1,2}$
匹配国内电话号码:^d{3}-d{8}|d{4}-d{7,8}$
评注:匹配形式如 010-12345678 或 0571-12345678 或 0831-1234567
匹配中国邮政编码:^[1-9]d{5}(?!d)$
匹配身份证:d{14}(d{4}|(d{3}[xX])|d{1})
评注:中国的身份证为 15 位或 18 位
不能为空且二十字节以上:^[s|S]{20,}$
字符匹配
匹配由 26 个英文字母组成的字符串:^[A-Za-z]+$
匹配由 26 个大写英文字母组成的字符串:^[A-Z]+$
匹配由 26 个小写英文字母组成的字符串:^[a-z]+$
匹配由数字和 26 个英文字母组成的字符串:^[A-Za-z0-9]+$
匹配由数字、26个英文字母或者下划线组成的字符串:^w+$
匹配空行:n[s| ]*r
匹配任何内容:[sS]*
匹配中文字符:[x80-xff]+ 或者 [xa1-xff]+
只能输入汉字:^[x80-xff],{0,}$
匹配双字节字符(包括汉字在内):[^x00-xff]
匹配数字
只能输入数字:^[0-9]*$
只能输入n位的数字:^d{n}$
只能输入至少n位数字:^d{n,宋体"> 只能输入m-n位的数字:^d{m,n}$
匹配正整数:^[1-9]d*$
匹配负整数:^-[1-9]d*$
匹配整数:^-?[1-9]d*$
匹配非负整数(正整数 + 0):^[1-9]d*|0$
匹配非正整数(负整数 + 0):^-[1-9]d*|0$
匹配正浮点数:^[1-9]d*.d*|0.d*[1-9]d*$
匹配负浮点数:^-([1-9]d*.d*|0.d*[1-9]d*)$
匹配浮点数:^-?([1-9]d*.d*|0.d*[1-9]d*|0?.0+|0)$
匹配非负浮点数(正浮点数 + 0):^[1-9]d*.d*|0.d*[1-9]d*|0?.0+|0$
匹配非正浮点数(负浮点数 + 0):^(-([1-9]d*.d*|0.d*[1-9]d*))|0?.0+|0$
其他
匹配HTML标记的正则表达式(无法匹配嵌套标签):<(S*?)[^>]*>.*?</1>|<.*? />
匹配网址 URL :[a-zA-z]+://[^s]*
匹配 IP 地址:((25[0-5]|2[0-4]d|[01]?dd?).){3}(25[0-5]|2[0-4]d|[01]?dd?)
匹配完整域名:[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+.?
(编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!