一、正则表达式的介绍:
正则表达式是用于描述字符排列和匹配模式的一种语法规则。它主要用于字符串的模式分割、匹配、查找及替换操作。
1. 用途:匹配、查找、替换、分割
2. php提供了两套正则表达式函数库
*1. Perl 兼容正则表达式函数(推荐使用)
2. POSIX 扩展正则表达式函数
二、 语法:
1. 表达式的格式: "/表达式/[修正符]"
解释:其中"/"表示正则表达式的定界符,但是也可以是其他符号:如”#“,”!“
注意:定界符不可以是字母、数字和斜线\。
像“#”、“|”、“!”等都可以的
如:/.../ #...# |....|
其中修正符是可选的,表示对表达式做额外的修饰。
三、组成部分
1、原子
2、定界符
通常使用“/”作为定界符开始和结束。也可以使用“#”,而使用“#”的另一个作用就是当字符串中有很多“/”字符时,就不需要对其转义,比如uri
通常在使用preg_match的结果数组第0个将包含与整个匹配的字符串
3、修饰符
3.1、不区分大小写
正则表达式最后一个"i"就是修饰符,表示忽略大小写进行匹配
3.2、忽略空格
如果最后一位位"x"表示忽略空格
3.3、"s"表示匹配视为单行(就是可以让点.支持换行)
3.4、"U"拒绝贪婪匹配
4、 元字符(具有特殊意义字符):
5、普通转义字符
四、预查
4.1、断言某些字符串中某些字符的存在与否,它分为两种
正向预查:(?=) 相对应的 (?!)表示否定意思
反向预查:(?<=) 相对应的 (?<!)表示否定意思
4.2、字符宽度判断
匹配的时候只做一个判断,本身是不占位置的。
/HE(?=L)LLO/ 与HELLO匹配,
而/HE(?=L)LO/与HELLO是不匹配的。毕竟但从字节数上两者就是不匹配的,前者只有4个,而后者有5个。
五、捕获数据
5.1、没有指明类型而进行的分组,将会被获取,供以后使用。
> 指明类型指的是通配符。所以只有圆括号起始位置没有问号的才能被捕捉。
> 在同一个表达式内的引用叫做反向引用。
> 调用格式: \编号(如\1)。
5.2、捕获组
5.2.1、pattern模式,也是常用的捕获模式
5.2.2、?P<name>pattern 模式,通过设置的name直接快速调用结果
5.2.3、\num 捕获,是对捕获组的反向引用。 例如\2表示第二个子组匹配值,\表示第一个子组匹配值
5.2.4、\k< name > 是对命名捕获组的反向引用。其中 name 是捕获组名。
5.3、非捕获组(?:pattern)
与(pattern)的唯一区别是,匹配pattern但不捕获匹配结果
六、懒性匹配
格式:限定符?
原理:"?":如果前面有限定符,会使用最小的数据。如“*”会取0个,而“+”会取1个,如过是{3,5}会取3个
七、注释
格式:(?# 注释内容)
用途:主要用于复杂的注释
案例一:判断url是否包含csdn
案例三: 判断字符串”I am a good boy”中是否包含3个相同的字母
8.2、替换
案例一:将字符串”hello,中国”中的hello替换为′你好′
案例三:将字符串中”abc45gfegeedp3iorfe67k321k”;中出现的连续两个数字改为第二个数字,如字符串中13被改为3
九、php中贪婪匹配与惰性匹配
十、中文匹配
1、UTF8汉字编码范围:0x4e00 - 0x9fa5 , 并使用u模式修正符
2、ANSI(gb2312)汉字编码范围:0xb0 - 0xf7, 0xa1 - 0xfe
正则表达式是用于描述字符排列和匹配模式的一种语法规则。它主要用于字符串的模式分割、匹配、查找及替换操作。
1. 用途:匹配、查找、替换、分割
2. php提供了两套正则表达式函数库
*1. Perl 兼容正则表达式函数(推荐使用)
2. POSIX 扩展正则表达式函数
二、 语法:
1. 表达式的格式: "/表达式/[修正符]"
解释:其中"/"表示正则表达式的定界符,但是也可以是其他符号:如”#“,”!“
注意:定界符不可以是字母、数字和斜线\。
像“#”、“|”、“!”等都可以的
如:/.../ #...# |....|
其中修正符是可选的,表示对表达式做额外的修饰。
三、组成部分
1、原子
> 单个字符、数字,如a-z,A-Z,0-9。
> 模式单元,如(ABC)为由多个原子组成的大的原子。
> 原子表,如 [ABC]。
> 重新使用的模式单元,如:\\1
> 普通转义字符,如:\d, \D, \w
> 转义元字符,如:\*,\.
> 元字符
2、定界符
通常使用“/”作为定界符开始和结束。也可以使用“#”,而使用“#”的另一个作用就是当字符串中有很多“/”字符时,就不需要对其转义,比如uri
通常在使用preg_match的结果数组第0个将包含与整个匹配的字符串
//使用定界符“/”
<?php
$regex = '/^http:\/\/([\w.]+)\/([\w]+)\/([\w]+)\.html$/i';
$str = 'http://www.youku.com/show_page/id_1234.html';
$matches = array();
if(preg_match($regex, $str, $matches)){
var_dump($matches);
}
//结果
array (size=4)
0 => string 'http://www.youku.com/show_page/id_1234.html' (length=46)
1 => string 'www.youku.com' (length=13)
2 => string 'show_page' (length=9)
3 => string 'id_1234' (length=10)
//使用定界符“#”
<?php
$regex = '#^http://([\w.]+)/([\w]+)/([\w]+)\.html$#i';
$str = 'http://www.youku.com/show_page/id_1234.html';
$matches = array();
if(preg_match($regex, $str, $matches)){
var_dump($matches);
}
//结果
array (size=4)
0 => string 'http://www.youku.com/show_page/id_1234.html' (length=43)
1 => string 'www.youku.com' (length=13)
2 => string 'show_page' (length=9)
3 => string 'id_1234' (length=7)
3、修饰符
3.1、不区分大小写
正则表达式最后一个"i"就是修饰符,表示忽略大小写进行匹配
<?php
$regex = '/HELLO/';
$str = 'hello';
$matches = array();
if(preg_match($regex, $str, $matches)){
echo 'No i=>Valid Successful!',"\n";
}
$regex = '/HELLO/i';
if(preg_match($regex, $str, $matches)){
echo 'YES i=>Valid Successful!',"\n";
}
//结果
YES i=>Valid Successful!
3.2、忽略空格
如果最后一位位"x"表示忽略空格
3.3、"s"表示匹配视为单行(就是可以让点.支持换行)
3.4、"U"拒绝贪婪匹配
4、 元字符(具有特殊意义字符):
[] 表示单个字符的原子表
例如:[aoeiu] 表示任意一个元音字母
[0-9] 表示任意一位数字
[a-z][0-9]表示小写字和一位数字构成的两位字符
[a-zA-Z0-9] 表示任意一位大小字母或数字
[^] 表示除中括号内原子之外的任何字符 是[]的取反
例如:[^0-9] 表示任意一位非数字字符
[^a-z] 表示任意一位非小写字母
{m} 表示对前面原子的数量控制,表示是m次
例如:[0-9]{4} 表示4为数字
[1][3-8][0-9]{9} 手机号码
{m,} 表示对前面原子的数量控制,表示是至少m次
例如: [0-9]{2,} 表示两位及以上的数字
{m,n}表示对前面原子的数量控制,表示是m到n次
例如: [a-z]{6,8} 表示6到8位的小写字母
* 表示对前面原子的数量控制,表示是任意次,等价于{0,}
+ 表示对前面原子的数量控制,表示至少1次,等价于{1,}
? 表示对前面原子的数量控制,表示0次或1次(可有可无) 等价于{0,1}
例如:正整数:[1-9][0-9]*
整数:[\-]?[0-9]+
() 表示一个整体原子,【还有一个子存储单元的作用】。
也可以使用?:来拒绝子存储。 (?:.*?)
例如:(red) 字串red
(rea|blue) 字串red或blue
(abc){2} 表示两个abc
| 表示或的意思
(rea|blue) 字串red或blue
^ 用在正则单元块的开头处,表示必须以指定的开头
$ 用在正则单元块的结尾处,表示必须以指定的结尾
. 表示任意一个除换行符之外的字符
常用组合: .*? 表示最小匹配所有字符(拒绝贪婪匹配)
5、普通转义字符
\d 匹配一个数字;等价于[0-9]
\D 匹配除数字以外任何一个字符;等价于[^0-9]
\w 匹配一个英文字母、数字或下划线;等价于[0-9a-zA-Z_]
\W 匹配除英文字母、数字和下划线以外任何一个字符;等价于[^0-9a-zA-Z_]
\s 匹配一个空白字符;等价于[\f\n\r\t\v]
\S 匹配除空白字符以外任何一个字符;等价于[^\f\n\r\t\v]
\oNN 匹配一个八进制数字
\xNN 匹配一个十六进制数字
\cC 匹配一个控制字符
####不可打印显示的字符####
\a 报警 等价于 0x07
\b 退格 等价于 0x08
\f 匹配一个换页符等价于 \x0c 或 \cL
\n 匹配一个换行符;等价于 \x0a 或 \cJ
\r 匹配一个回车符等价于\x0d 或 \cM
\t 匹配一个制表符;等价于 \x09\或\cl
\v 匹配一个垂直制表符;等价于\x0b或\ck
四、预查
4.1、断言某些字符串中某些字符的存在与否,它分为两种
正向预查:(?=) 相对应的 (?!)表示否定意思
反向预查:(?<=) 相对应的 (?<!)表示否定意思
<?php
$regex = '/(?<=c)d(?=e)/'; /* d 前面紧跟c, d 后面紧跟e*/
$str = 'abcdefgk';
$matches = array();
if(preg_match($regex, $str, $matches)){
var_dump($matches);
}
//结果
d
<?php
$regex = '/(?<!c)d(?!e)/'; /* d 前面不紧跟c, d 后面不紧跟e*/
$str = 'abcdefgk';
$matches = array();
if(preg_match($regex, $str, $matches)){
var_dump($matches);
}else{
var_dump('no match');
}
//结果
no match
4.2、字符宽度判断
匹配的时候只做一个判断,本身是不占位置的。
/HE(?=L)LLO/ 与HELLO匹配,
而/HE(?=L)LO/与HELLO是不匹配的。毕竟但从字节数上两者就是不匹配的,前者只有4个,而后者有5个。
五、捕获数据
5.1、没有指明类型而进行的分组,将会被获取,供以后使用。
> 指明类型指的是通配符。所以只有圆括号起始位置没有问号的才能被捕捉。
> 在同一个表达式内的引用叫做反向引用。
> 调用格式: \编号(如\1)。
<?php
$regex = '/^(Chuanshanjia)[\w\s!]+\1$/';
$str = 'Chuanshanjia thank Chuanshanjia';
$matches = array();
if(preg_match($regex, $str, $matches)){
var_dump($matches);
}
//运行结果
array (size=2)
0 => string 'Chuanshanjia thank Chuanshanjia' (length=31)
1 => string 'Chuanshanjia' (length=12)
5.2、捕获组
5.2.1、pattern模式,也是常用的捕获模式
<?php
$regex = '/(ab(c)+)+d(e)?/';
$str = 'abccde';
$matches = array();
if(preg_match($regex, $str, $matches)){
print_r($matches);
}
//结果
Array ( [0] => abccde [1] => abcc [2] => c [3] => e )
5.2.2、?P<name>pattern 模式,通过设置的name直接快速调用结果
<?php
$regex = '/(?P<group1>\w(?P<group2>\w))abc(?P<group3>\w)45/';
$str = 'fsabcd45';
$matches = array();
if(preg_match($regex, $str, $matches)){
print_r($matches);
}
//结果
Array ( [0] => fsabcd45 [group1] => fs [1] => fs [group2] => s [2] => s [group3] => d [3] => d )
5.2.3、\num 捕获,是对捕获组的反向引用。 例如\2表示第二个子组匹配值,\表示第一个子组匹配值
<?php
$regex = '/(\w)(\w)\2\1/';
$str = 'abba';
$matches = array();
if(preg_match($regex, $str, $matches)){
print_r($matches);
}
//结果
Array ( [0] => abba [1] => a [2] => b )
5.2.4、\k< name > 是对命名捕获组的反向引用。其中 name 是捕获组名。
<?php
$regex='/(?P<name>\w)abc\k<name>/';
$str="fabcf";
preg_match_all($regex, $str,$matches);
print_r($matches);
//结果
Array ( [0] => Array ( [0] => fabcf ) [name] => Array ( [0] => f ) [1] => Array ( [0] => f ) )
5.3、非捕获组(?:pattern)
与(pattern)的唯一区别是,匹配pattern但不捕获匹配结果
六、懒性匹配
格式:限定符?
原理:"?":如果前面有限定符,会使用最小的数据。如“*”会取0个,而“+”会取1个,如过是{3,5}会取3个
<?php
$regex = '/heL*/i';
$str = 'heLLLLLLLLLLLLLLLL';
if(preg_match($regex, $str, $matches)){
var_dump($matches);
}
//heLLLLLLLLLLLLLLLL
$regex = '/heL*?/i';
$str = 'heLLLLLLLLLLLLLLLL';
if(preg_match($regex, $str, $matches)){
var_dump($matches);
}
//he
$regex = '/heL+?/i';
$str = 'heLLLLLLLLLLLLLLLL';
if(preg_match($regex, $str, $matches)){
var_dump($matches);
}
//heL
$regex = '/heL{3,10}?/i';
$str = 'heLLLLLLLLLLLLLLLL';
if(preg_match($regex, $str, $matches)){
var_dump($matches);
}
//heLLL
七、注释
格式:(?# 注释内容)
用途:主要用于复杂的注释
<?php
$regex = '/
^host=(?<!\.)([\d.]+)(?!\.) (?#主机地址)
\|
([\w!@#$%^&*()_+\-]+) (?#用户名)
\|
([\w!@#$%^&*()_+\-]+) (?#密码)
(?!\|)$/ix';
$str = 'host=192.168.10.221|root|123456';
$matches = array();
if(preg_match($regex, $str, $matches)){
var_dump($matches);
}
//结果
array (size=4)
0 => string 'host=192.168.10.221|root|123456' (length=31)
1 => string '192.168.10.221' (length=14)
2 => string 'root' (length=4)
3 => string '123456' (length=6)
八、php 中应用正则表达式
preg_grep -- 返回与模式匹配的数组单元
* preg_match_all -- 进行全局正则表达式匹配 , 返回共计匹配的个数。
和下面的一样,不同的是匹配到最后(全局匹配)
* preg_match -- 进行正则表达式匹配,只匹配一次,返回1,否则0,
格式:preg_match("正则表达式","被匹配的字串",存放结果的变量名,PREG_OFFSET_CAPTURE,起始偏移量)
其中:PREG_OFFSET_CAPTURE表示获取匹配索引位置
起始偏移量:从指定位置开始匹配
preg_quote -- 转义正则表达式字符
preg_split -- 用正则表达式分割字符串
preg_replace -- 执行正则表达式的搜索和替换
8.1、查找
8.1.1、不使用正则表达式
strstr函数
string strstr ( string haystack,mixedneedle [, bool $before_needle = false ])
注1:haystack是当事字符串,needle是被查找的字符串。该函数区分大小写。
注2:返回值是从needle开始到最后。
注3:关于$needle,如果不是字符串,被当作整形来作为字符的序号来使用。
注4:before_needle若为true,则返回前东西。
stristr函数与strstr函数相同,只是它不区分大小写
strpo函数
int strpos ( string haystack,mixedneedle [, int $offset = 0 ] )
注1:可选的 offset 参数可以用来指定从 haystack 中的哪一个字符开始查找。返回的数字位置是相对于 haystack 的起始位置而言的。
stripos -查找字符串首次出现的位置(不区分大小定)
strrpos -计算指定字符串在目标字符串中最后一次出现的位置
strripos -计算指定字符串在目标字符串中最后一次出现的位置(不区分大小写)
8.1.2、使用正则表达式
在php中,提供了preg_math()和preg_match_all函数进行正则匹配
int preg_match|preg_match_all ( string $pattern , string $subject [, array &$matches [, int $flags = 0 [, int $offset = 0 ]]] )
搜索subject与pattern给定的正则表达式的一个匹配.
pattern:要搜索的模式,字符串类型。
subject :输入字符串。
matches:如果提供了参数matches,它将被填充为搜索结果。 matches[0]将包含完整模式匹配到的文本,matches[1]将包含第一个捕获子组匹配到的文本,以此类推。
flags:flags可以被设置为以下标记值:PREG_OFFSET_CAPTURE 如果传递了这个标记,对于每一个出现的匹配返回时会附加字符串偏移量(相对于目标字符串的)。 注意:这会改变填充到matches参数的数组,使其每个元素成为一个由 第0个元素是匹配到的字符串,第1个元素是该匹配字符串 在目标字符串subject中的偏移量。
offset:通常,搜索从目标字符串的开始位置开始。可选参数 offset 用于 指定从目标字符串的某个未知开始搜索(单位是字节)。
返回值:preg_match()返回 pattern 的匹配次数。 它的值将是0次(不匹配)或1次,因为 preg_match()在第一次匹配后 将会停止搜索。 preg_match_all()不同于此,它会一直搜索subject直到到达结尾。 如果发生错误 preg_match()返回 FALSE。
案例一:判断url是否包含csdn
$str='http://blog.csdn.net/hsd2012';
$pattern='/csdn/';
var_dump(preg_match($pattern,$str));
//结果,表示查到
1
案例二:判断字符串”I am a good boy”中是否包含单词go
<?php
//判断字符串”I am a good boy”中是否包含单词go
$str='I am a good boy, go go';
$pattern='/\bgo\b/';//单词限定符
var_dump(preg_match($pattern,$str, $matches));//结果为1,表示有找到单词 go
案例三: 判断字符串”I am a good boy”中是否包含3个相同的字母
<?php
$str='I am a good boy';
$pattern='/(\w).*\1.*\1/';
preg_match($pattern,$str, $matches);
var_dump($matches);
//结果
array (size=2)
0 => string 'ood bo' (length=6)
1 => string 'o' (length=1)
8.2、替换
8.2.1、不使用正则替换
php中当替换字符串的时候,如果不适用正则,我们通常使用substr、mb_substr、str_replace、substr_replace关于这几个函数
str_replace(find,replace,string,count)str_replace(find,replace,string,count)
使用一个字符串替换字符串中的另一些字符
find 必需。规定要查找的值。
replace 必需。规定替换 find 中的值的值。
string 必需。规定被搜索的字符串。
count 可选。一个变量,对替换数进行计数。
substr_replace(string,replacement,start,length)
把字符串的一部分替换为另一个字符串。适合用于替换自定位置的字符串。
string 必需。规定要检查的字符串。
replacement 必需。规定要插入的字符串。
start 必需。规定在字符串的何处开始替换。
8.2.2、使用php中提供了preg_replace _callback和preg_replace 函数
mixed preg_replace ( mixed pattern,mixed replacement , mixed subject[,intlimit = -1 [, int &count]])
函数功能描述:在字符串subject中,查找pattern,然后使用replacement 去替换,如果有limit则代表限制替换limit次。
pregreplacecallback与pregreplace功能相识,不同的是pregreplaceback使用一个回调函数callback来代替replacement
案例一:将字符串”hello,中国”中的hello替换为′你好′
如果不是用正则:
str=’hello,中国’;
str=str_replace(′hello′,′你好′,str)
或是使用str=substr_replace(str,’你好’,0,5)
使用正则
pattern=′/hello/′;
str=preg_replace (pattern,′你好′,str);
<?php
$str='abbbcvdfddddereeefefghgghjg';
$pattern='/(.)\1/';
$str=preg_replace($pattern,'',$str);
var_dump($str);//abcvdferefefghhjg
案例三:将字符串中”abc45gfegeedp3iorfe67k321k”;中出现的连续两个数字改为第二个数字,如字符串中13被改为3
<?php
$str='abc45gfegeedp3iorfe67k321k';
$pattern='/(\d)(\d)/';
$str=preg_replace($pattern,'$2', $str);
var_dump($str);//abc5gfegeedp3iorfe7k21k
解析:$n在正则表达式外使用反向引用。n代表第几次匹配到的结果
8.3、分割
php提供了explode函数去分割字符串,与其对应的是implode。关于explode原型如下:
array explode ( string delimiter,stringstring [, int $limit ] )
delimiter:边界上的分隔字符。
string:输入的字符串。
limit:如果设置了 limit 参数并且是正数,则返回的数组包含最多 limit 个元素,而最后那个元素将包含 string 的剩余部分。
如果 limit 参数是负数,则返回除了最后的 -limit 个元素外的所有元素。如果 limit 是 0,则会被当做 1。
关于通过正则表达式进行字符串分割,php提供了split、preg_split 函数。preg_split() 函数,通常是比 split() 更快的替代方案。
array preg_split ( string pattern,stringsubject [, int limit=−1[,intflags = 0 ]] )
<?php
$str='http://127.0.0.1/linux/webApi/test.php';
$str=explode('/', $str);
var_dump($str);
//结果
array (size=6)
0 => string 'http:' (length=5)
1 => string '' (length=0)
2 => string '127.0.0.1' (length=9)
3 => string 'linux' (length=5)
4 => string 'webApi' (length=6)
5 => string 'test.php' (length=8)
$str='http://127.0.0.1/linux/webApi/test.php';
$pattern='/\//'; /*因为/为特殊字符,需要转移*/
$str=preg_split ($pattern, $str);
var_dump($str);
//结果
0 => string 'http:' (length=5)
1 => string '' (length=0)
2 => string '127.0.0.1' (length=9)
3 => string 'linux' (length=5)
4 => string 'webApi' (length=6)
5 => string 'test.php' (length=8)
九、php中贪婪匹配与惰性匹配
贪婪匹配:就是匹配尽可能多的字符。
比如,正则表达式中m.*n,它将匹配最长以m开始,n结尾的字符串。
如果用它来搜索manmpndegenc的话,它将匹配到的字符串是manmpndegen而非man。
可以这样想,当匹配到m的时候,它将从后面往前匹配字符n。
懒惰匹配:就是匹配尽可能少的字符。
有的时候,我们需要并不是去贪婪匹配,而是尽可能少的去匹配。这时候,就需要将其转为惰性匹配。
怎样将一个贪婪匹配转为惰性匹配呢?只需要在其后面添加一个”?”即可。
如m.*?n将匹配manmpndegenc,匹配到的字符串是man。
*? 零次或多次,但尽可能少的匹配
+? 一次或多次,但尽可能少的匹配
?? 0次或1次,但尽可能少的匹配
{n,}? 至少n次,但尽可能少的匹配
{n,m}? n到m次 ,但尽可能少的匹配
十、中文匹配
1、UTF8汉字编码范围:0x4e00 - 0x9fa5 , 并使用u模式修正符
2、ANSI(gb2312)汉字编码范围:0xb0 - 0xf7, 0xa1 - 0xfe