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 登录记住密码实现思路
May 07 PHP
PHP实现数字补零功能的2个函数介绍
May 12 PHP
php获取用户浏览器版本的方法
Jan 03 PHP
thinkPHP学习笔记之安装配置篇
Mar 05 PHP
PHP.ini安全配置检测工具pcc简单介绍
Jul 02 PHP
简单了解PHP编程中数组的指针的使用
Nov 30 PHP
PHP面向对象编程之深入理解方法重载与方法覆盖(多态)
Dec 24 PHP
php简单解析mysqli查询结果的方法(2种方法)
Jun 29 PHP
关于ThinkPHP中的异常处理详解
May 11 PHP
PHP实现的分解质因数操作示例
Aug 01 PHP
PHP连接sftp并下载文件的方法教程
Aug 26 PHP
Laravel5框架自定义错误页面配置操作示例
Apr 17 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
推荐10个提供免费PHP脚本下载的网站
2014/12/31 PHP
ThinkPHP自定义函数解决模板标签加减运算的方法
2015/07/03 PHP
PHP实现上传图片到 zimg 服务器
2016/10/19 PHP
微信公众号模板消息群发php代码示例
2016/12/29 PHP
Yii2中简单的场景使用介绍
2017/06/02 PHP
php判断IP地址是否在多个IP段内
2020/08/18 PHP
两个DIV等高的JS的实现代码
2007/12/23 Javascript
jQuery事件 delegate()使用方法介绍
2012/10/30 Javascript
JS对HTML标签select的获取、添加、删除操作
2013/10/17 Javascript
使用javascript实现ListBox左右全选,单选,多选,全请
2013/11/07 Javascript
js实现的二级横向菜单条实例
2015/08/22 Javascript
浅析JS动态创建元素【两种方法】
2016/04/20 Javascript
JS基于面向对象实现的选项卡效果示例
2016/12/20 Javascript
Vue实现动态添加或者删除对象和对象数组的操作方法
2018/09/21 Javascript
javascript关于“时间”的一次探索
2019/07/24 Javascript
[53:13]2014 DOTA2国际邀请赛中国区预选赛5.21 DT VS LGD-GAMING
2014/05/22 DOTA
[01:33:07]VGJ.T vs Newbee Supermajor 败者组 BO3 第一场 6.6
2018/06/07 DOTA
[53:44]DOTA2-DPC中国联赛 正赛 PSG.LGD vs Magma BO3 第一场 1月31日
2021/03/11 DOTA
利用python批量修改word文件名的方法示例
2017/10/17 Python
单链表反转python实现代码示例
2018/02/08 Python
Python中安装easy_install的方法
2018/11/18 Python
Linux下Pycharm、Anaconda环境配置及使用踩坑
2018/12/19 Python
python Pandas库基础分析之时间序列的处理详解
2019/07/13 Python
python线程安全及多进程多线程实现方法详解
2019/09/27 Python
pandas参数设置的实用小技巧
2020/08/23 Python
python 基于UDP协议套接字通信的实现
2021/01/22 Python
逼真的HTML5树叶飘落动画
2016/03/01 HTML / CSS
丝绸和人造花卉、植物和树木:Nearly Natural
2018/11/28 全球购物
鲜果饮品店创业计划书
2014/01/21 职场文书
公司年会主持词
2014/03/22 职场文书
公司合作协议书范本
2014/04/18 职场文书
普通话宣传标语
2014/06/26 职场文书
个园导游词
2015/02/04 职场文书
党员进社区活动总结
2015/05/07 职场文书
专项资金申请报告
2015/05/15 职场文书
Python中的变量与常量
2021/11/11 Python