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面向对象编程快速入门
Dec 14 PHP
浅析PHP水印技术
Feb 14 PHP
dede3.1分页文字采集过滤规则详说(图文教程)
Apr 03 PHP
PHP在特殊字符前加斜杠的实现代码
Jul 17 PHP
PHP基础学习之流程控制的实现分析
Apr 28 PHP
Codeigniter操作数据库表的优化写法总结
Jun 12 PHP
php时间戳格式化显示友好的时间函数分享
Oct 21 PHP
PHP结合jQuery.autocomplete插件实现输入自动完成提示的功能
Apr 27 PHP
探究Laravel使用env函数读取环境变量为null的问题
Dec 06 PHP
PHP进制转换实例分析(2,8,16,36,64进制至10进制相互转换)
Feb 04 PHP
php利用imagemagick实现复古老照片效果实例
Feb 16 PHP
PHP基于DateTime类解决Unix时间戳与日期互转问题【针对1970年前及2038年后时间戳】
Jun 13 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
从C/C++迁移到PHP——判断字符类型的函数
2006/10/09 PHP
不使用php api函数实现数组的交换排序示例
2014/04/13 PHP
Linux下php5.4启动脚本
2014/08/03 PHP
[原创]PHP获取数组表示的路径方法分析【数组转字符串】
2017/09/01 PHP
Django中通过定时任务触发页面静态化的处理方式
2018/08/29 PHP
PHP 多进程与信号中断实现多任务常驻内存管理实例方法
2019/10/04 PHP
JQuery 写的个性导航菜单
2009/12/24 Javascript
jQuery 下拉列表 二级联动插件分享
2012/03/29 Javascript
基于jquery DOM写的类似微博发布的效果
2012/10/20 Javascript
Javascript中valueOf与toString区别浅析
2013/03/19 Javascript
获取数组中最大最小值方法js代码(自写)
2013/08/12 Javascript
5个数组Array方法: indexOf、filter、forEach、map、reduce使用实例
2015/01/29 Javascript
jquery实现鼠标滑过显示二级下拉菜单效果
2015/08/24 Javascript
JS+CSS实现经典的左侧竖向滑动菜单效果
2015/09/23 Javascript
JavaScript中运算符规则和隐式类型转换示例详解
2017/09/06 Javascript
详解JS取出两个数组中的不同或相同元素
2019/03/20 Javascript
ES6 Array常用扩展的应用实例分析
2019/06/26 Javascript
vue指令v-html使用过滤器filters功能实例
2019/10/25 Javascript
Javascript和jquery在selenium的使用过程
2019/10/31 jQuery
Vue结合路由配置递归实现菜单栏功能
2020/06/16 Javascript
Python复制文件操作实例详解
2015/11/10 Python
Python实现Smtplib发送带有各种附件的邮件实例
2017/06/05 Python
Ubuntu18.04中Python2.7与Python3.6环境切换
2019/06/14 Python
Python pytesseract验证码识别库用法解析
2020/06/29 Python
Python基础教程(一)——Windows搭建开发Python开发环境
2020/07/20 Python
Selenium python时间控件输入问题解决方案
2020/07/22 Python
CSS3哪些新特性值得称赞
2016/03/02 HTML / CSS
html5手机端页面可以向右滑动导致样式受影响的问题
2018/06/20 HTML / CSS
Superdry极度干燥美国官网:英国制造的服装品牌
2018/11/13 全球购物
英国在线定制百叶窗网站:Swift Direct Blinds
2020/02/25 全球购物
绩效专员岗位职责
2013/12/02 职场文书
小学生防溺水广播稿
2014/01/12 职场文书
专业技术人员年度考核评语
2014/12/31 职场文书
2015迎新晚会开场白
2015/05/29 职场文书
告诉你创业计划书的8个实用技巧
2019/07/12 职场文书
超详细Python解释器新手安装教程
2021/05/10 Python