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)

(9)匹配中文:

$pattern = '/^[\x{4e00}-\x{9fa5}]+$/u';