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编程最快明白》第五讲:php目录、文件操作
Nov 01 PHP
PHP大批量数据操作时临时调整内存与执行时间的方法
Apr 20 PHP
php验证手机号码(支持归属地查询及编码为UTF8)
Feb 01 PHP
shell脚本作为保证PHP脚本不挂掉的守护进程实例分享
Jul 15 PHP
分享自定义的几个PHP功能函数
Apr 15 PHP
php编写批量生成不重复的卡号密码代码
May 14 PHP
基于php实现随机合并数组并排序(原排序)
Nov 26 PHP
使用Huagepage和PGO来提升PHP7的执行性能
Nov 30 PHP
PHP编写daemon process详解及实例代码
Sep 30 PHP
Laravel框架路由和控制器的绑定操作方法
Jun 12 PHP
PHP迭代器和生成器用法实例分析
Sep 28 PHP
Laravel5.1 框架响应基本用法实例分析
Jan 04 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
php使用cookie显示用户上次访问网站日期的方法
2015/01/26 PHP
php die()与exit()的区别实例详解
2016/12/03 PHP
详解thinkphp实现excel数据的导入导出(附完整案例)
2016/12/29 PHP
PHP空值检测函数与方法汇总
2017/11/19 PHP
PHP接入支付宝接口失效流程详解
2020/11/10 PHP
javascript延时重复执行函数 lLoopRun.js
2007/06/29 Javascript
JavaScript onkeydown事件入门实例(键盘某个按键被按下)
2014/10/17 Javascript
js闭包实现按秒计数
2015/04/23 Javascript
javascript实现的登陆遮罩效果汇总
2015/11/09 Javascript
js阻止默认浏览器行为与冒泡行为的实现代码
2016/05/15 Javascript
JQuery异步加载PartialView的方法
2016/06/07 Javascript
详解AngularJs中$sce与$sceDelegate上下文转义服务
2016/09/21 Javascript
微信小程序多张图片上传功能
2017/06/07 Javascript
JavaScript重复元素处理方法分析【统计个数、计算、去重复等】
2017/12/14 Javascript
微信小程序实现通过js操作wxml的wxss属性示例
2018/12/06 Javascript
详解vue中多个有顺序要求的异步操作处理
2019/10/29 Javascript
jquery实现商品sku多属性选择功能(商品详情页)
2019/12/20 jQuery
es6 for循环中let和var区别详解
2020/01/12 Javascript
python应用程序在windows下不出现cmd窗口的办法
2014/05/29 Python
在Django的模型中添加自定义方法的示例
2015/07/21 Python
Django 项目布局方法(值得推荐)
2020/03/22 Python
Python 实现3种回归模型(Linear Regression,Lasso,Ridge)的示例
2020/10/15 Python
英国著名书店:Foyles
2018/12/01 全球购物
第一范式(1NF)、第二范式(2NF)和第三范式(3NF)之间的区别是什么?
2016/04/28 面试题
七年级政治教学反思
2014/02/03 职场文书
环境保护与污染治理求职信
2014/07/16 职场文书
转让协议书范本
2014/09/13 职场文书
村委会贫困证明范文
2014/09/21 职场文书
股权转让协议书
2014/12/07 职场文书
单方投资意向书
2015/05/11 职场文书
教师实习自我鉴定总结
2019/08/20 职场文书
pycharm2021激活码使用教程(永久激活亲测可用)
2021/03/30 Python
vue点击弹窗自动触发点击事件的解决办法(模拟场景)
2021/05/25 Vue.js
常用的MongoDB查询语句的示例代码
2021/07/25 MongoDB
MySQL日期时间函数知识汇总
2022/03/17 MySQL
如何使用python包中的sched事件调度器
2022/04/30 Python