PHP正则表达式之捕获组与非捕获组


Posted in PHP onNovember 06, 2015

今天遇到一个正则匹配的问题,忽然翻到有捕获组的概念,手册上也是一略而过,百度时无意翻到C#和Java中有对正则捕获组的特殊用法,搜索关键词有PHP时竟然没有相关内容,自己试了一下,发现在PHP中也是可行的,于是总结一下,分享的同时也希望有大神和细心的学习者找到我理解中出现的问题。

什么是捕获组

捕获组语法:

字符  描述 示例
(pattern) 匹配pattern并捕获结果,自动设置组号。  (abc)+d 匹配abcd或者abcabcd
(?pattern) 或 (?'name'pattern) 匹配pattern并捕获结果,设置name为组名。  
\num 对捕获组的反向引用。其中 num 是一个正整数。 (\w)(\w)\2\1 匹配abba
\k 或 \k' name ' 对命名捕获组的反向引用。其中 name 是捕获组名。 (?\w)abc\k 匹配xabcx

我们先看一下PHP的正则匹配函数

int preg_match ( string $pattern , string $subject [, array &$matches [, int $flags = 0 [, int $offset = 0 ]]] )

前面两项是我们常用的,$pattern是正则匹配模式,$string是要匹配的字符串。

array &$match,它是一个数组,&表示匹配出来的结果会被写入$match中。

int $flags 如果传递了这个标记, 对于每一个出现的匹配返回时会附加字符串偏移量(相对于目标字符串的)。

int $offset 用于指定从目标字符串的某个未知开始搜索(单位是字节)。

我们主要看一下$match的值里会有什么:

$mode = '/a=(\d+)b=(\d+)c=(\d+)/';
$str='**a=4b=98c=56**';
$res=preg_match($mode,$str,$match);
var_dump($match);

结果如下:

array (size=4)
  0 => string 'a=4b=98c=56' (length=11)
  1 => string '4' (length=1)
  2 => string '98' (length=2)
  3 => string '56' (length=2)

现在我们知道了什么是捕获组,捕获组是正则表达示中以()括起来的部分,每一对()是一个捕获组。

PHP会为它编号,从1开始。至于为什么会从1开始,那是因为PHP把匹配到的完整字符串编号为0。

如果有多个括号或嵌套括号,按左边括号出现的顺序来进行编号,如图:

PHP正则表达式之捕获组与非捕获组

按图中的匹配模式匹配时,捕获组的123号分别是红绿蓝。

捕获组的忽略与命名

我们还可以阻止PHP为匹配组的编号:在匹配组中模式前加  ?:

$mode = '/a=(\d+)b=(?:\d+)c=(\d+)/';

这样,匹配结果就会变成:

array (size=3)
 0 => string 'a=4b=98c=56' (length=11)
 1 => string '4' (length=1)
 2 => string '56' (length=2)

当然,我们也可以在括号的内部为它给它独特的名字。

命名子组可以接受(?<name>), (?'name') 以及(?P<name>)语法. 之前版本仅接受(?P<name>)语法.

例如:$mode = '/a=(\d+)b=(?P<sec>\d+)c=(\d+)/';

使用时结果为:

array (size=5)
 0 => string 'a=4b=98c=56' (length=11)
 1 => string '4' (length=1)
 'sec' => string '98' (length=2)
 2 => string '98' (length=2)
 3 => string '56' (length=2)

在保留索引数组的同时,加上一个关联项,key值为捕获组名。

捕获组的反向引用

我们在用preg_replace()函数进行正则替换时,我们还可以使用 \n 或 $n 来引用第n个捕获组.

$mode = '/a=(\d+)b=(\d+)c=(\d+)/';
$str='**a=4b=98c=56**';
$rp='\1/$2/\3/';
echo preg_replace($mode,$rp,$str);//**4/98/56/**

\1表示捕获组1(4),$2为捕获组2(98),\3为捕获组3(56)。

非捕获组的用法:

非捕获组语法:

字符  描述 示例
(?:pattern) 匹配pattern,但不捕获匹配结果。 'industr(?:y|ies) 匹配'industry'或'industries'。
(?=pattern) 零宽度正向预查,不捕获匹配结果。 'Windows (?=95|98|NT|2000)' 匹配 "Windows2000" 中的 "Windows" 不匹配 "Windows3.1" 中的 "Windows"。
(?!pattern) 零宽度负向预查,不捕获匹配结果。 'Windows (?!95|98|NT|2000)' 匹配 "Windows3.1" 中的 "Windows" 不匹配 "Windows2000" 中的 "Windows"。
(? 零宽度正向回查,不捕获匹配结果。 '2000 (?
(? 零宽度负向回查,不捕获匹配结果。 '2000 (?

为什么称为非捕获组呢?那是因为它们有捕获组的特性,在匹配模式的()中,但是匹配时,PHP不会为它们编组,它们只会影响匹配结果,并不作为结果输出。

/d(?=xxx)    匹配"后面是xxx的一个数字"。

注意格式:只能放在匹配模式字符串之后!

例如:

$pattern='/\d(?=abc)/';
$str="ab36abc8eg";
$res=preg_match($pattern,$str,$match);
var_dump($match);//6

匹配的6,因为只有它作为一个数字,后面还有abc。

(?<=xxx) /d 匹配"前面是xxx的一个数字"

注意格式:只能放在匹配模式字符串之前!

例如:

$pattern='/(?<=abc)\d/';
$str="ab36abc8eg";
$res=preg_match($pattern,$str,$match);
var_dump($match);//8

匹配的8,因为只有它作为一个数字,后面还有abc。

与(?=xxx)  (?<=xxx)相对的是(?!=xxx)  (?<!=xxx) 它们在=前加了非运算符 “!”

它表示前面/后面不是xxx的字符串,这里就不再举例了。

如果您觉得本博文对您有帮助,您可以推荐或关注我,如果您有什么问题,可以在下方留言讨论,谢谢。

PHP 相关文章推荐
利用PHP动态生成VRML网页
Oct 09 PHP
php escape URL编码
Dec 10 PHP
PHP中几个常用的魔术常量
Feb 23 PHP
PHP关于IE下的iframe跨域导致session丢失问题解决方法
Oct 10 PHP
PHP OPP机制和模式简介(抽象类、接口和契约式编程)
Jun 09 PHP
php通过ksort()函数给关联数组按照键排序的方法
Mar 18 PHP
PHP使用ODBC连接数据库的方法
Jul 18 PHP
关于PHP开发的9条建议
Jul 27 PHP
php常用数组array函数实例总结【赋值,拆分,合并,计算,添加,删除,查询,判断,排序】
Dec 07 PHP
PHP中使用mpdf 导出PDF文件的实现方法
Oct 22 PHP
Laravel框架实现的批量删除功能示例
Jan 16 PHP
Laravel5.7 Eloquent ORM快速入门详解
Apr 12 PHP
php创建无限级树型菜单
Nov 05 #PHP
详解PHP中instanceof关键字及instanceof关键字有什么作用
Nov 05 #PHP
PHP递归创建多级目录
Nov 05 #PHP
PHP中的静态变量及static静态变量使用详解
Nov 05 #PHP
PHP环境中Memcache的安装和使用
Nov 05 #PHP
php生成gif动画的方法
Nov 05 #PHP
浅析PHP中call user func()函数及如何使用call user func调用自定义函数
Nov 05 #PHP
You might like
Codeigniter校验ip地址的方法
2015/03/21 PHP
通过MSXML2自动获取QQ个人头像及在线情况(给初学者)
2007/01/22 Javascript
url地址自动加#号问题说明
2010/08/21 Javascript
收集的一些Array及String原型对象的扩展实现代码
2010/12/05 Javascript
js切换div css注意的细节
2012/12/10 Javascript
jquery对象和DOM对象的区别介绍
2013/08/09 Javascript
JavaScript将取代AppleScript?
2014/09/18 Javascript
详谈JavaScript内存泄漏
2014/11/14 Javascript
javascript原始值和对象引用实例分析
2015/04/25 Javascript
JavaScript基本数据类型及值类型和引用类型
2015/08/25 Javascript
浅谈$('div a') 与$('div&gt;a')的区别
2016/07/18 Javascript
js窗口震动小程序分享
2016/11/28 Javascript
jQuery之动画ajax事件(实例讲解)
2017/07/18 jQuery
vue2利用Bus.js如何实现非父子组件通信详解
2017/08/25 Javascript
JS实现多功能计算器
2020/10/28 Javascript
Python实现抓取城市的PM2.5浓度和排名
2015/03/19 Python
Python中二维列表如何获取子区域元素的组成
2017/01/19 Python
Python3.遍历某文件夹提取特定文件名的实例
2018/04/26 Python
使用Django开发简单接口实现文章增删改查
2019/05/09 Python
Python导入父文件夹中模块并读取当前文件夹内的资源
2020/11/19 Python
Python基于Faker假数据构造库
2020/11/30 Python
用python实现一个简单的验证码
2020/12/09 Python
Android本地应用打开方法——通过html5写连接
2016/03/11 HTML / CSS
利物浦足球俱乐部官方商店(美国):Liverpool FC US
2019/10/09 全球购物
大学生简单自荐信
2013/11/10 职场文书
制冷与空调专业毕业生推荐信
2014/07/07 职场文书
护士辞职信怎么写
2015/02/27 职场文书
2015年国税春训心得体会
2015/03/09 职场文书
法学专业求职信范文
2015/03/19 职场文书
2015年全国保险公众宣传日活动方案
2015/05/06 职场文书
企业法人代表证明书
2015/06/18 职场文书
篮球比赛通讯稿
2015/07/18 职场文书
煤矿安全生产工作总结
2015/08/13 职场文书
2016大学生优秀志愿者事迹材料
2016/02/25 职场文书
用python画城市轮播地图
2021/05/28 Python
利用js实现简单开关灯代码
2021/11/23 Javascript