在php提供的系列函数中,使用这种规则对字符串进行匹配、查找、替换及分割等操作,其应用非常广泛。例如常见的使用正则表达式去验证用户在表单中提交的用户名、密码、E-mail地址、身份证号码、电话号码及个人主页等是否合法,如果成功则插入到数据库中返回注册成功等字样,否则提示提交的数据中有非法字符、注册失败等。此外,除了在Perl、C#及Java语言中应用外,在B/S软件开发中,Linux操作系统、前台JavaScript脚本、后台脚本php以及在mysql数据中都可以使用正则表达式。还有在捕获字符串的能力上,正则表达式也可以很好的完成工作,如截取URL的域名或者其他的内容。
其缺点如下:
(1)正则表达式值匹配文本字面,不匹配文本意义
(2)容易引起性能问题。像“.”、“*”等很容易造成大量的回溯,使性能有很大的下降,所以编写好的正则表达式要对正则引擎执行方式有很清楚的理解才可以
(3)正则表达式的替换功能较差,甚至没有基本的截取字符串或者把首字母变成大小写的功能,这对URL重写引擎时有致命的影响
看正则表达式的小实例
1. "/^https?\:\/\/(\w+){3}\.(\w+)\.(\w+)/" //匹配http://www.baidu.com 2. "/^[1-9]\[0-9xX]/" //一种简单的匹配身份证号码的正则代码 3. "/^0([1,8]+){1,2}\-[2-9](\d+){5,6}/" //匹配中国大陆的座机电话号码
元字符 |
函数功能概述 |
preg_match() |
执行一个正则表达式匹配 |
preg_match_all() |
进行全局正则表达式匹配 |
preg_replace() |
执行正则表达式的搜索与替换 |
preg_split() |
用正则表达式分割字符串 |
preg_grep() |
返回匹配模式的数组条目 |
2、正则表达式的语法规则
一个完整的正则表达式由三部分组成:元字符、定界符和原子
(1) 原子 原子是最基本的单位,原子包括所有的大小写字母、所有数字、所有标点符号以及其他的一些字符,例如,a~z、A~Z、0~9、双引号“"”、单引号“'”以及@等。
(2) 定界符 在服务器的脚本语言中,一般使用Perl兼容的正则表达式,即通常正则表达式都放置在“/”和“/”之间,但定界符又不仅仅局限于“/”,除了字母、数字和正斜杠“\”以外的任何字符都可以作为定界符。
(3) 元字符 所谓元字符就是用于构建正则表达式的具有特殊含义的字符,例如“*”、“+”、"?"等。如果在正则表达式中包含元字符本身,使其失去特殊含义,则必须在前面加上“\”进行转义,正则表达式的元字符。
如下表所示:
元字符 |
功能意义概述 |
\s |
匹配任意一个空白字符,等价于[\f\n\r\t\v] |
\S |
匹配除空白字符以外的任何一个字符,等价于[^\f\n\r\t\v] |
\w |
匹配任意一个数字、字母或下划线,等价于[0-9A-Za-z_] |
* |
匹配0次、1次或多次前面的原子 |
+ |
匹配一次或多次前面的原子 |
? |
匹配0次或1次前面的原子 |
. |
匹配除了换行符以外的任何一个字符 |
| |
匹配两个或多个分支选择 |
{m} |
匹配前一个内容,重复次数为m次 |
{m,} |
匹配前一个内容,重复次数大于等于m次 |
{m,n} |
匹配前一个内容,重复次数为m次到n次 |
^或\A |
匹配输入字符串的开始位置 |
$或\Z |
匹配输入字符串的结束位置 |
\b |
匹配单词的边界 |
\B |
匹配除单词边界以外的部分 |
[] |
匹配方括号中指定的任意一个原子 |
[^] |
匹配方括号中的原子以外的任意一个字符 |
0 |
匹配整体为一个原子,即模式单元 |
构造正则表达式和创建字符表达式的方法相似,就是用多种字符与操作符将小的表达式结合在一起来创建更大的表达式。正则表达式的组件可以使单个字符、字符集合、字符范围、字符间的选择或者这些组建的任意组合。
记住正则表达式的口令: 正则其实也势利,削尖头来把钱揣; (指开始符号^和结尾符号$)
特殊符号认不了,弄个倒杠来引路; (指\. \*等特殊符号)
倒杠后面跟小w, 数字字母来表示; (\w跟数字字母;\d跟数字)
倒杠后面跟小d, 只有数字来表示;
倒杠后面跟小a, 报警符号嘀一声;
倒杠后面跟小b, 单词分界或退格;
倒杠后面跟小t, 制表符号很明了;
倒杠后面跟小r, 回车符号知道了;
倒杠后面跟小s, 空白符号很重要;
小写跟罢跟大写,多得实在不得了;
倒杠后面跟大W, 字母数字靠边站;
倒杠后面跟大S, 空白也就靠边站;
倒杠后面跟大D, 数字从此靠边站;
倒框后面跟大B, 不含开头和结尾;
单个字符要重复,三个符号来帮忙; (* + ?)
0 星加1 到无穷,问号只管0 和1; (*表0-n;+表1-n;?表0-1次重复)
花括号里学问多,重复操作能力强; ({m} {m,} {m,n})
若要重复字符串,园括把它括起来; ((abc){3} 表示字符串“abc”重复3次 )
特殊集合自定义,中括号来帮你忙;
转义符号行不通,一个一个来排队;
实在多得排不下,横杠请来帮个忙; ([1-5])
尖头放进中括号,反义定义威力大; ([^a]指除“a”外的任意字符 )
1竖作用可不小,两边正则互替换; (键盘上与“\”是同一个键)
1竖能用很多次,复杂定义很方便;
园括号,用途多;
反向引用指定组,数字排符对应它; (“\b(\w+)\b\s+\1\b”中的数字“1”引用前面的“(\w+)”)
支持组名自定义,问号加上尖括号; (“(?<Word>\w+)”中把“\w+”定义为组,组名为“Word”)
园括号,用途多,位置指定全靠它;
问号等号字符串,定位字符串前面; (“\b\w+(?=ing\b)”定位“ing”前面的字符串)
若要定位串后面,中间插个小于号; (“(?<=\bsub)\w+\b”定位“sub”后面的字符串)
问号加个惊叹号,后面跟串字符串;
PHPer都知道, !是取反的意思;
后面不跟这一串,统统符合来报到; (“\w*d(?!og)\w*”,“dog”不符合,“do”符合)
问号小于惊叹号,后面跟串字符串;
前面不放这一串,统统符合来报到;
点号星号很贪婪,加个问号不贪婪;
加号问号有保底,至少重复一次多;
两个问号老规矩,0次1次团团转;
花括号后跟个?,贪婪变成不贪婪;
还有很多装不下,等着以后来增加
3、正则表达式的优先级
在使用正则表达式的时候需要特别注意的是匹配的顺序,通常相同优先级是从左至右的顺序进行匹配,不同优先级的匹配顺序是先高后低。各中操作符的优先级匹配顺序从高到低顺序如下表所示
顺序 |
元字符 |
描述 |
1 |
\ |
转义符号 |
2 |
()、(?:)、(?=),、[] |
模式单元和原子表 |
3 |
*、+、?、{m}、{m,}、{m,n} |
重复匹配 |
4 |
^、$、\b、\B、\A、\Z |
边界限制 |
5 |
| |
模式选择 |
4、php正则表达式函数(兼容Perl)
正则表达式是定义字符串规则的一种模式,必须配合正则表达式中的函数应用,才能实现最字符串的匹配、查找、替换和分割等操作。另外在使用正则表达式处理大量信息的时候速度会大幅度的减慢,所以应当在处理比较复杂的字符串的时候才考虑使用正则表达式函数。
字符串的查找和匹配(一)
int preg_match(string $pattern, string $subject [, array &$matches [,int $flags=0 [,int $offset=0]]])
该函数有两个必要参数,第一个参数pattern是用户写的正则表达式,第二个参数subject是正则表达式要匹配的内容。如果提供了第三个可选的参数matches,则可以保存第一个参数中模式匹配的结果。
preg_match()函数的返回值是0次或1次,因为函数第一次匹配后会停止搜索。preg_match()与其不同,它会一直搜索subject直到到达结尾,如发生错误,pre_match()函数返回FALSE,如果正确则返回由数字索引的一个数组。如下列代码中:
<?php $pattern = '/^https?\:\/\/(\w+){3}\.(\w+)\.(\w+)/'; $subject = "http://www.58lxqy.com"; preg_match($pattern,$subject,$matches); print_r($matches); ?>
得到的结果如图所示:
Array( [0] => http://www.58lxqy.com [1] =>w [2] =>58lxqy.com [3] =>com )
字符串的匹配和查找(二)
int preg_match_all(string $pattern, string $subject, array &$matches [, int $flags=PREG_PATTERN_ORDER [, int offset =0]])
函数将所有可能的匹配结果放入第三个参数matches的数组中,并返回整个模式匹配的次数,如果出错则返回FALSE。
其中PREG_PATTERN_ORDER是preg_match_all()的默认值,用于对结果排序,使$matches[0]为全部模式匹配的数组,$matches[1]为第一个括号中的子模式所匹配的字符串组成的数组。也可以选择PREG_SET_ORDER的方式对结果进行排序,使$matches[0]为第一个括号中的子模式所匹配的字符串组成的数组,$matches[1]为全部模式匹配的数组。
如下例代码中:
<?php preg_match_all("/<[^>]+>(.*)</[^>]+>/U","<b>例如: </b><div>This is php100</div>",$arr); /**事实证明,原来默认是重复匹配(即包括相同的)我的理解是如果有多少个<b></b>,就匹配多少个,而加了U,时期不是默认的重复,相同的找到一个就可以,即不贪婪,默认是贪婪的。**/ echo $arr[0][0]. $arr[0][1] . "\n"; //arr[0]匹配全部模式“<[^>]+>(.*)</[^>]+>”,$arr[0][0]="<b>例如: </b>",$arr[0][1]="<div>This is php100</div>" echo $arr[1][0]. $arr[1][1] . "\n"; //arr[1]匹配第一个子模式“(.*)”,一次类推[2]匹配第二个子模式……$arr[0][0]="例如:",$arr[0][1]="This is php100" ?>
程序执行结果如下图所示:
例如: //加粗是因为带有<b></b> This is 58lxqy //换行是因为<div></div>独占一行 例如:This is 58lxqy
正则表达式的替换函数
preg_replace()函数是一个执行正则表达式的搜索和替换函数,它的使用也是基于Perl的正则表达式语法的
mixed preg_replace(mixed $pattern, mixed $replacement, mixed $subject[, int $limit=-1[,int &$count]])
该函数使用replacement替换所有pattern的所有出现,并返回修改后的结果。
preg_replace()函数的每个参数(除了limit)都可以是一个数组,如果pattern和replacement都是数组,将以其键名在数组中出现的顺序来进行处理。这不一定和索引的数字顺序相同(没有键名的默认是数字顺序,当然是相同的)。如果使用索引来表示哪个pattern被哪个replacement来替换,应该在调用preg_replace()函数之前用ksort()对数组进行排序。如下示例代码中:
<?php $string = array ("/(19|20)(\d{2})-(\d{1,2})-(\d{1,2})/", "/^\s*{(\w+)}\s*=/"); /*数组中第一个元素的正则表达式有4个子模式,1是(19|20),2是(\d{2}),3和4都是(\d{1,2})。数组中的第二个元素只有一个子模式(\w+),自然对应代号1*/ $replace = array ("\\3/\\4/\\1\\2", "$\\1 ="); /*此数组中第一个元素匹配string 数组中的第一个元素,\\3代表子模式1,\\4代表子模式4,”\\3/\\4/\\1\\2“代表替换后的顺序是3 4 1 2。而此数组中第二个元素匹配string数组中的第二个元素,\\1代表模式(\w+)*/ print preg_replace ($string, $replace, "{birthday} = 1990-07-09"); ?>
程序运行的结果如下图所示:
$birthday=07/09/1990
使用正则表达式函数分割函数
preg_split()函数是一个通过正则表达式分割字符串,返回一个数组,包含subject中沿着与pattern匹配的边界所分割的子串。如果指定了limit个子串,如果limit是-1,则意味着没有任何限制,可以用来继续指定可选参数flags。
array preg_split(string $pattern, string $subject [,int $limit=-1 [,int flags=0]])
参数说明:
pattern:用于搜索的模式,字符串形式
subject:输入字符串
limit:如果指定,将限制分割得到的子串最多只有limit个,返回的最后一子串将包含所有剩余部分。limit的值为-1、0或NULL时都代表“不限制”。在php中使用NULL可以跳过对flags的设置。
如下示例代码:
<?php $str = '58 lxqy . com'; $arr = preg_split('/ /', $str, -1); print_r($arr); ?>
上述脚本语言中,使用preg_split()函数分割字符串$str,由于字符串中有特定的分割字符,所以以空格截取该字符串,得到一个一维数组,如下所示:
Array( [0] => 58 [1] => lxqy [2] => . [3] => com )
安徽隆兴禽业(www.58lxqy.com)全年大量供应状元红鸡苗(红玉鸡苗)、固始鸡土鸡苗、淮南王土鸡苗,散养鸡苗,大红公鸡苗及各类土鸡种蛋。批发订购:13075005200 QQ:1170693418 地址:阜阳市太和县倪邱镇孙庙105国道东侧。
安徽鸡苗,阜阳鸡苗,安徽土鸡苗,阜阳土鸡苗,鸡苗孵化,河南鸡苗,山东鸡苗,河南土鸡苗,山东土鸡苗,固始鸡,淮南王,纯红肉杂,纯红公鸡。