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下载远程文件类(支持断点续传)
Nov 14 PHP
php 删除无限级目录与文件代码共享
Nov 22 PHP
PHP register_shutdown_function函数的深入解析
Jun 03 PHP
CURL的学习和应用(附多线程实现)
Jun 03 PHP
PHP生成条形码大揭秘
Sep 24 PHP
PHP正则匹配日期和时间(时间戳转换)的实例代码
Dec 14 PHP
thinkPHP5.0框架整体架构总览【应用,模块,MVC,驱动,行为,命名空间等】
Mar 25 PHP
laravel5.4生成验证码的实例讲解
Aug 05 PHP
PHP面向对象中new self()与 new static()的区别浅析
Aug 17 PHP
PHP绕过open_basedir限制操作文件的方法
Jun 10 PHP
PHP convert_cyr_string()函数讲解
Feb 13 PHP
php实现商城购物车的思路和源码分析
Jul 23 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 xfocus防注入资料
2008/04/27 PHP
PHP数组内存耗用太多问题的解决方法
2010/04/05 PHP
PHP实现通过文本文件统计页面访问量功能示例
2019/02/13 PHP
JavaScript 组件之旅(三):用 Ant 构建组件
2009/10/28 Javascript
javascript各浏览器中option元素的表现差异
2011/04/07 Javascript
使用JQuery和CSS模拟超链接的用户单击事件的实现代码
2012/05/23 Javascript
JavaScript自定义事件介绍
2013/08/29 Javascript
jQuery判断checkbox(复选框)是否被选中以及全选、反选实现代码
2014/02/21 Javascript
JavaScript焦点事件、鼠标事件和滚轮事件使用详解
2016/01/15 Javascript
JS实现超简单的汉字转拼音功能示例
2016/12/22 Javascript
JS 在数组指定位置插入/删除数据的方法
2017/01/12 Javascript
解决微信内置浏览器返回上一页强制刷新问题方法
2017/02/05 Javascript
jQuery 中msgTips 顶部弹窗效果实现代码
2017/08/14 jQuery
在vue项目中使用element-ui的Upload上传组件的示例
2018/02/08 Javascript
使用watch在微信小程序中实现全局状态共享
2019/06/03 Javascript
bootstrap-treeview实现多级树形菜单 后台JSON格式如何组织?
2019/07/26 Javascript
VUE table表格动态添加一列数据,新增的这些数据不可以编辑(v-model绑定的数据不能实时更新)
2020/04/03 Javascript
深入分析JavaScript 事件循环(Event Loop)
2020/06/19 Javascript
vue设置全局访问接口API地址操作
2020/08/14 Javascript
Javascript前端下载后台传来的文件流代码实例
2020/08/18 Javascript
python 示例分享---逻辑推理编程解决八皇后
2014/07/20 Python
python实现基本进制转换的方法
2015/07/11 Python
浅谈python requests 的put, post 请求参数的问题
2019/01/02 Python
djang常用查询SQL语句的使用代码
2019/02/15 Python
numpy中三维数组中加入元素后的位置详解
2019/11/28 Python
纯CSS3实现移动端展开和收起效果的示例代码
2020/04/26 HTML / CSS
Html5+CSS3+EL表达式问题小结
2020/12/19 HTML / CSS
西班牙最大的在线滑板和街头服饰商店:Fillow.net
2019/04/15 全球购物
项目考察欢迎辞
2014/01/17 职场文书
工作迟到检讨书
2014/02/21 职场文书
最新农村养殖致富:资金投入较低的创业项目有哪些?
2019/09/26 职场文书
Python趣味挑战之实现简易版音乐播放器
2021/05/28 Python
Pandas数据类型之category的用法
2021/06/28 Python
python flappy bird小游戏分步实现流程
2022/02/15 Python
使用SQL实现车流量的计算的示例代码
2022/02/28 SQL Server
Netty分布式客户端接入流程初始化源码分析
2022/03/25 Java/Android