PHP正则表达式
说明:根据《PHP核心技术与最佳实践》做的一点笔记。
如有错误或建议,请指教。
一、PHP有两套正则函数:
(1)由PCRE库提供的函数,以前缀“preg_”命名,PCRE意思是兼容Perl的正则表达式的缩写首字母。
(2)由POSIX扩展提供的函数,以前缀“ereg_”命名,POSIX意思是UNIX可移植操作系统接口的首字母。
注意:自PHP5.3以后,不再推荐使用POSIX正则函数库,会报Deprecated级别的错误。
二、正则表达式的组成:
一个正则表达式分为三个部分:分隔符、表达式、修饰符。
三、测试工具:
(1)RegexTester。
(2)Firefox的扩展Regular Expression Tester。
四、常用的pcre函数:
常用函数一:preg_match()和preg_match_all():
(1)preg_match($pattern,$str,[$matches])
preg_match()返回 pattern 的匹配次数。
它的值将是0次(不匹配)或1次,因为preg_match()在第一次匹配后 将会停止搜索
(2)preg_match_all($pattern,$str,[$matches])。
返回完整匹配次数(可能是0),或者如果发生错误返回FALSE
示例:
$res = preg_match_all('/(foo)(bar)(baz)/', 'foobarbaz', $matches);var_dump($res);//结果:int 1 var_dump($matches);
打印结果:
array (size=4) 0 => array (size=1) 0 => string 'foobarbaz' (length=9) 1 => array (size=1) 0 => string 'foo' (length=3) 2 => array (size=1) 0 => string 'bar' (length=3) 3 => array (size=1) 0 => string 'baz' (length=3)
常用函数二:preg_filter和preg_replace
功能:执行一个正则表达式搜索并替换。
preg_filter只返回匹配到的替换后的结果。
preg_replace返回完整的替换后的字符串。
参数顺序(每个参数可以是字符串,也可以是数组):
preg_filter($pattern, $replace, $str)
preg_replace($pattern, $replace, $str)
示例:
1、当$str是字符串时,两个函数效果一样。
$str = '2019年08月14日';
$pattern = array('/年/','/月/','/日/');
$replace = array('-','-','');
$a = preg_filter($pattern, $replace, $str);
var_dump($a);//结果:2019-08-14
$a = preg_replace($pattern, $replace, $str);
var_dump($a);//结果:2019-08-14
2、当$str是数组时,两个函数效果不一样。
$str = array('2019年08月14日','2018-01-06','闰年','一年');
$pattern = array('/年/','/月/','/日/');
$replace = array('-','-','');
$a = preg_filter($pattern, $replace, $str);
var_dump($a);
$a = preg_replace($pattern, $replace, $str);
var_dump($a);
结果分别是:
array (size=3)
0 => string '2019-08-14' (length=10)
2 => string '闰-' (length=4)
3 => string '一-' (length=4)
array (size=4)
0 => string '2019-08-14' (length=10)
1 => string '2018-01-06' (length=10)
2 => string '闰-' (length=4)
3 => string '一-' (length=4)
preg_replace_callback()执行一个正则表达式搜索并且使用一个回调进行替换.
示例:
$str = '2019年08月14日';
$pattern = array('/年/','/月/','/日/');
$res = preg_replace_callback($pattern, function($matches){
return '-';
}, $str);
var_dump($res);
结果:string '2019-08-14-'
常用函数三:preg_last_error
功能:返回最后一个PCRE正则执行产生的错误代码
示例:
preg_match('/(?:\D+|<\d+>)*[!?]/', 'foobar foobar foobar');
if (preg_last_error()) {
print preg_last_error();
}
常用函数四:preg_grep($pattern,$arr,$flags)
功能:返回给定数组中与模式pattern 匹配的元素组成的数组.
若flags设置为PREG_GREP_INVERT时,返回不匹配的元素组成的数组。
示例:
$arr = array('php','html','js','java','jquery','python');
$pattern = '/p/';
$res = preg_grep($pattern,$arr);
var_dump($res);
$res = preg_grep($pattern,$arr,PREG_GREP_INVERT);
var_dump($res);
array (size=2)
0 => string 'php' (length=3)
5 => string 'python' (length=6)
array (size=4)
1 => string 'html' (length=4)
2 => string 'js' (length=2)
3 => string 'java' (length=4)
4 => string 'jquery' (length=6)
常用函数五:preg_split()
功能:通过一个正则表达式分隔字符串.
返回数组,失败返回false。
示例:
以字符串中的空格和,分割字符串成数组
$str = 'php , html , js , javascript';
$keywords = preg_split("/[\s,]+/",$str);
var_dump($keywords);
结果:
array (size=4)
0 => string 'php' (length=3)
1 => string 'html' (length=4)
2 => string 'js' (length=2)
3 => string 'javascript' (length=10)
五、正则表达式中的元字符:
. 匹配除换行以外的任意字符
\w 匹配字母或数字或下划线或汉字
\s 匹配任意空白字符
\d 匹配数字
\b 匹配单词开始或结束
^ 匹配字符串的开始
$ 匹配字符串的结束
- 表示范围
[] 匹配括号中的任意一个字符
*、+、?量词
六、转义:
如果要想查找元字符本身,就需要使用转义\。
例如:\\、\.、\*等。
使用\Q和\E包围的元字符也被忽略,
例如:
\Q.*\E 就是匹配.*,不是任意字符。
七、反义:
匹配相反时,可以用反义。
\W 匹配任意不是字母、数字、下划线、汉字的字符。
\S 匹配任意不是空白字符的字符
\D 匹配任意非数字的字符
\B 匹配不是单词开头或结束的位置
[^x] 匹配除了x以外的任意字符
[^aeiou] 匹配除了aeiou这几个字符以外的字符
八、分支:
“|”表示分支。
示例:
[a|bc]d 表示匹配ad或bcd
当都是单字符时:[a|b|c] 等同于[abc]
九、分组:
使用小括号()进行分组.
示例:
匹配IP地址 (\d{1,3}\.){3}\d{1,3}
十、常用模式:
i 表示忽略大小写。
m 多行匹配,仅当字符串中有换行符\n时才起作用。
. 作用是使表达式里的元字符.匹配换行符
U 懒惰模式
u 字符串被当成utf-8
十一、环视:
(1)顺序肯定环视,语法(?=exp),意思是匹配以exp结尾的前面的部分。
示例:匹配以ing结尾的单词的前面部分
/\d\w+(?=ing\b)/
(2)逆序肯定环视,语法(?<=exp),意思是匹配exp后面的部分
示例:匹配以re开头的单词的后面部分
/(?<=re\b)\w+\b/
注意:环视不会占用字符,也就是说,环视它就是看一下是不是,但并不会匹配它,也就不会占用这个字符。
环视可以用来匹配html闭合标签里的内容,例如<div></div><h1></h1>等比较方便。
示例:
需求:匹配html的标题title中的内容:
$str = file_get_contents('http://localhost/index.html');
$pattern = '/(?<=<title>).*(?=<\/title>)/';
$res = preg_match_all($pattern,$str,$matches);
var_dump($res);//结果:int 1
var_dump($matches);
//结果:
array (size=1)
0 =>
array (size=1)
0 => string 'test' (length=4)
十二、运算符优先级:
转义符 > 括号和中括号 > 限定符
十三、关于分隔符:
正则表达式的分隔符只要遵循规则,是可以随意使用的。
例如:
$pattern = '/php/';
$pattern = '#php#';
$pattern = '~php~';
$pattern = '%php%';
这些都是可以的
十四、附加:
(1)\b示例:
\ba\w*\b 匹配以a开头的单词(注意是单词,不是字符串,^才是以什么开头的字符串)。
$str = 'hello php,hello js'; $pattern = '/\bhello\b/'; $replace = 'nihao'; $a = preg_filter($pattern, $replace,$str); var_dump($a);
结果:string 'nihao php,nihao js'
结论:被\b包围起来的表示是单独一个单词。
\babc\b 表示字符串中的abc是单词,
'abc'、'hello abc' 是正确的,
'abcd'、'helloabc'都是不正确的。
(2)等同写法:
[0-9]和\d一样,表示一位数字。
如果只考虑英文的话,[a-zA-Z_]和\w相同。
(3)关于^的使用:
当用作表示只能以字符开头时,只能用在正则表达式的最前端。
当用作取反时,只能用在字符组中,即中括号里。
(4)贪婪和懒惰匹配模式:
贪婪就是尽可能多地匹配字符。
懒惰就是尽可能少地匹配字符。
(5)可能发生的错误:
preg_match_all(): Unknown modifier 't'
分析错误原因:这种情况多数是由定界符的问题引起的.
解决方法:找到需要转义的特殊字符,加\转义一下。
(6)分组[^]的使用示例:
$str = 'abv vvv bac'; $pattern = '/[^ab]/'; $res = preg_match_all($pattern,$str,$matches); var_dump($res);//结果:int 7 var_dump($matches);
结果:
array (size=1) 0 => array (size=7) 0 => string 'v' (length=1) 1 => string ' ' (length=1) 2 => string 'v' (length=1) 3 => string 'v' (length=1) 4 => string 'v' (length=1) 5 => string ' ' (length=1) 6 => string 'c' (length=1)
说明:使用[]分组时,如果使用^非指定字符匹配时,整个分组里的都是不要匹配的。
即:/[^ab]/ 表示不匹配a,也不匹配b。
(7)示例,匹配html网页里的所有图片:
$str = file_get_contents('http://localhost/index.html'); $pattern = '/<img[^>]*?src=[\'|"]([^\'">]*?)[\'"][^>]*?>/'; $res = preg_match_all($pattern,$str,$matches); var_dump($res);//结果:int 2 var_dump($matches);
结果:
array (size=2) 0 => array (size=2) 0 => string '<img width="180" height="100" src='http://localhost/img/1.png' >' 1 => string '<img width="180" src='http://localhost/img/2.png' height="100">' 1 => array (size=2) 0 => string 'http://localhost/img/1.png' 1 => string 'http://localhost/img/2.png'
(8)示例:匹配div的内容:
$str = '<div class="content">hello</div>'; $pattern = '#<div[^>]*?>([^<]*)<\/div>#'; $res = preg_match_all($pattern,$str,$matches); var_dump($res);//1 var_dump($matches);
结果:
array (size=2) 0 => array (size=1) 0 => string '<div class="content">hello</div>' (length=32) 1 => array (size=1) 0 => string 'hello' (length=5)