文档章节

正则表达式中的子组模式

snowing1990
 snowing1990
发布于 2016/03/14 16:47
字数 1816
阅读 55
收藏 1
点赞 1
评论 0

作者:西瓜玩偶(racnil070512 at hotmail dot com)

一、基础知识

在PCRE正则表达式中,我们可以利用圆括号定义一个子组,我们可以使用preg_match函数(其他函数的信息请参考PHP官方API文档)的第三个参数捕获圆括号中匹配的内容:

preg_match('#color\h*:\h*([A-Za-z]*)#', 'color: red', $matches);
print_r($matches);


运行的结果为:

Array
(
    [0] => color: red
    [1] => red
)


根据定义,子组(正则表达式中圆括号)中的内容会按照左半边括号出现的顺序,将匹配的内容分别存放至$matches数组中,下标从1开始(下标0的内容为整个匹配的字符串)。

这个特性可以让我们很方便地从被匹配的字符串中提取我们需要的信息。PCRE中的子组的功能其实非常强大,但是PHP官方的API文档并没有对齐作过多的介绍。下面的文章尝试对PCRE中的子组功能做一个初步的介绍。

二、匹配顺序

子组其中一个重要的作用就是用来描述“分支”的匹配,但是如果较短的分支是较长分支的前缀的话,那么较短的分支一定要放在较长的分支后面:

'#(eq|lte|gte|lt|gt)#'


注意,这里的lt必须放在lte的后面,否则的话正则表达式解析器读到lt时分支就已经匹配成功了,那么lte就永远不会被匹配到。

三、非捕获子组

有些时候子组只是用来描述“分支”的匹配的,我们并不想让最后的$matches里面出现括号里的内容,此时可以用非捕获子组(?:)告诉正则表达式解析器,它不需要被捕获:

'#(?:https?|ftp)://([A-Za-z\.]+)#'


这样,URL里面主机名部分就会被存放至$matches数组下标为1的域内。而前面的https?|ftp虽然也被打了圆括号,但是由于圆括号中有?:,所以并不会被保存到$matches中。

不过这里仅仅是举例子,在实际应用中,可以调用parse_url函数来更好地完成获取主机名的任务。

四、前向探测(Lookahead)

前向探测的目的是,在当前的点,向后读入内容(对于读取匹配内容的程序来说,它即将读入的内容被称为“前”;但是对于阅读者来说,即将读入的内容被
称为“后”),判断其是否与子组中的正则表达式相匹配。如果匹配,则继续匹配后面的内容,否则匹配失败。虽然前向探测会向后读入内容,但是被读入的内容并
不会被“消耗”掉,也不算做正则表达式匹配的一部分,也就是说,后面的正则表达式依然可以匹配到向后读入的内容。

如果这样说不太明白,可以看看下面的例子。利用(?=)就可以构造一个前向探测:

'#\d*(?= mm)#'

这个正则表达式会匹配如'100 mm'这样的字符串。由于前向探测的正则表达式mm并不属于正则表达式的一部分,所以最后整个表达式(注意,不是$matches下标为1的域,而是整个表达式,也就是下标0)匹配出来的结果是'100'。

更好的例子是检查密码是否符合规范:

'#^(?=\w{8,20}$)(?=[^A-Z]*[A-Z])(?=[^a-z]*[a-z])(?=\D*\d)(?=[^_]*_).*$#'

这个正则表达式在最开头的地方依次使用了5个前向探测子组,分别检查密码长度在8至20之间、含有大写字母、含有小写字母、含有数字以及含有下划线。只有当这五个条件都满足,正则表达式才会继续向下匹配。由于这些子组都不会消耗读入的内容,所以最后我们简单地使用一个.*就可以获取整个密码字符串。

五、前向逆探测(Negative Lookahead)

与前向探测类似,只不过子组中的表达式必须不满足才行。它的构造方法为(?!):

'#\d*(?!\d| mm)#'


这个表达式除了类似于'100 mm'以外其余的类似于'100 cm'这样的字符串都可以被匹配。注意子组正则表达式里面加了一个\d,因为不加它,当读入'100 mm'的时候,表达式还是会匹配到'10',这是因为'0 mm'不匹配' mm'。

六、后向探测(Lookbehind)

与前向探测类似,后向探测只不过是以当前点为准,向前读入内容。后向探测的构造方法为(?<=):

'#(?<=EUR ).*#'

这个正则表达式会匹配'EUR 100'这样的字符串。匹配结果为'100'而不是'EUR 100',这是因为后向探测是以当前点为准,向前读入内容,这也就意味着,当开始进行最后.*的匹配时,'EUR '早已被读过了。

不过这并不意味着后向探测会消耗内容,只是因为我们并没有在正则表达式中匹配'EUR '而已。如果你有兴趣,可以尝试下面的表达式:

'#EUR (?<=EUR)\d*#'

这样,匹配出来的结果就是'EUR 100'了。

七、后向逆探测(Negative Lookbehind)

与后向探测类似,只不过子组内的表达式必须不匹配。这里就不再举例了。

八、命名子组

我们可以利用下面的语法命名一个子组:

'#(?P<prefix>A+)C#'


它会匹配类似于'AAAAC'的字符串,子组匹配的内容'AAAA'不仅会以数字下标保存(这个例子中为1),亦会以字符串下标('prefix')保存在$matches里面。

九、子组的重复利用

利用下面的方式我们可以重复利用已经在正则表达式中出现的子组:

'#(\w+) (?1)#'

这个正则表达式会匹配'foo bar'。不过需要注意的是,重用的子组并不会被捕获。如果想要捕获重用的子组,则应该在子组外面再加上一个括号:

'#(\w+) ((?1))#'

我们甚至可以通过子组名称来重复利用它:

'#(?<pattern>\w+) (?&pattern)#'

甚至还可以递归地调用子组:

'#(\w+, (?1)?)(\w+)#'

上面的表达式会匹配'foo, bar, baz, qux'。

十、重置分支

这一点在PHP官方文档中已经提到了:

'#(?:(Sat)ur|(Sun))day#'

当匹配'Sunday'的时候,我们会发现在$matches里面下标为1的域是空的,这是因为它尝试过匹配(Sat),由于没有匹配到内容,所以它在$matches里面加入了一个空的匹配项。如果要去掉这个恼人的匹配项,我们需要在匹配不成功的时候重置分支:

'#(?|(Sat)ur|(Sun))day#'

将原来的冒号改为竖线之后,我们就会发现,原来空的匹配不见了。

十一、总结

上面的文章中介绍了PCRE中子组的使用方法,并且简单地介绍了九种子组的特殊功能。如果能够灵活地、适当地运用在我们的程序中,它就可以帮助我们省掉许多字符串处理的步骤。


本文转载自:

共有 人打赏支持
snowing1990
粉丝 4
博文 90
码字总数 2952
作品 0
程序员
Python中正则表达式(re模块)的使用

Python中正则表达式(re模块)的使用 1、正则表达式的概述 (1)概述:正则表达式是一些由字符和特殊符号组成的字符串,他们描述了模式的重复或者表示多个字符,正则表达式能按照某种模式匹配...

Dayi_123
2017/05/05
0
0
JavaScript的String类型replace()方法介绍和使用replace()方法实现简单html模板替换功能

JavaScript字符串的replace()方法介绍 为了简化替换子字符串的操作,ECMAScript提供了replace()方法。这个方法接收两个参数:第一个参数可以是一个字符串(这个字符串不会转换成正则表达...

AAASSSSddd
2016/09/09
62
0
python核心编程笔记chapter 15

特殊符号和字符: 管道符号(|) 匹配多个正则表达式模式。 匹配任意一个单个的字符(.) 从字符串的开头或结尾或单词边界开始匹配。(^ $ b B) 创建字符类([]):使用方括号的正则表达式会...

MRFung
2016/01/06
22
0
python模块之re正则表达式

一、简单介绍 正则表达式是一种小型的、高度专业化的编程语言,并不是python中特有的,是许多编程语言中基础而又重要的一部分。在python中,主要通过re模块来实现。 正则表达式模式被编译成一...

张立达
2017/05/03
0
0
python模块之re正则表达式

一、简单介绍 正则表达式是一种小型的、高度专业化的编程语言,并不是python中特有的,是许多编程语言中基础而又重要的一部分。在python中,主要通过re模块来实现。 正则表达式模式被编译成一...

xmgdc
2017/07/03
0
0
Java魔法堂:深入正则表达式API

目录                               一、前言 二、正则表达式的使用诉求 三、java.util.regex包 四、java.lang.String实例 五、最短路径实现诉求 六、Java支...

fsjohnhuang
2014/11/16
0
0
java.util.regex Pattern 正则

/**String 中 replaceAll(),matches(),split() 等方法,都是调用Pattern中的方法。学习了,瞬间觉得Pattern强大了 public String replaceAll(String regex, String replacement) {return Pat......

happycode
2014/04/02
0
1
正则匹配原理之——逆序环视深入

前几天在CSDN论坛遇到这样一个问题: var str="8912341253789"; 需要将这个字符串中的重复的数字给去掉,也就是结果89123457。 首先需要说明的是,这种需求并不适合用正则来实现,至少,正则...

落枫眠
2012/02/11
0
0
chapter15 正则表达式

核心编程 正则表达式使用的特殊符号和字符 记号 说明 举例 literal 匹配字符串的值 foo re1|re2 匹配字符串1或者2 foo|bar . 匹配任意字符(换行符除外) b.b ^ 匹配字符串的开始 ^bar $ 匹配...

happyliferao
2015/03/15
0
0
正则表达式 学习参考 推荐入门者看

正则表达式(Regular Expression)是一种匹配模式,描述的是一串文本的特征。 正如自然语言中“高大”、“坚固”等词语抽象出来描述事物特征一样,正则表达式就是字符的高度抽象,用来描述字符...

浮躁的码农
2015/08/14
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

垃圾回收算法

一 如何判断对象可以回收 1 引用计数法 思路大概为:给对象添加一个引用计数器,每当有一个地方引用它时,计数器值加1;当引用失效时,计数器减1;任何时刻计算器为0的对象就是不可能再被使用...

sen_ye
11分钟前
0
0
Activiti简介(学习总结一)

一、介绍 activiti是使用命令模式设计基于bpmn2.0的一款开源工作流引擎。 工作流简单举例:提交请假申请->经理审批->结束。这就是一个简单流程。activiti支持用户自定义流程。配置各个流程对...

沙shasha
11分钟前
0
0
VCL界面控件DevExpress VCL Controls发布v18.1.3|附下载

DevExpress VCL Controls是 Devexpress公司旗下最老牌的用户界面套包。所包含的控件有:数据录入,图表,数据分析,导航,布局,网格,日程管理,样式,打印和工作流等,让您快速开发出完美、...

Miss_Hello_World
12分钟前
0
0
加米谷大数据培训:云计算、大数据和人工智能之间的关系

一般谈云计算的时候会提到大数据、谈人工智能的时候会提大数据、谈人工智能的时候会提云计算……感觉三者之间相辅相成又不可分割。 一、云计算最初的目标 云计算最初的目标是对资源的管理,管...

加米谷大数据
17分钟前
1
0
java集合元素的默认大小

当底层实现涉及到扩容时,容器或重新分配一段更大的连续内存(如果是离散分配则不需要重新分配,离散分配都是插入新元素时动态分配内存),要将容器原来的数据全部复制到新的内存上,这无疑使...

竹叶青出于蓝
19分钟前
1
0
Java快速开发平台,JEECG 3.7.7闪电版本发布,增加多套主流UI代码生成器模板

JEECG 3.7.7 闪电版本发布,提供5套主流UI代码生成器模板 导读 ⊙平台性能优化,速度闪电般提升 ⊙提供5套新的主流UI代码生成器模板(Bootstrap表单+BootstrapTable列表\ ElementUI列表表单)...

Jeecg
22分钟前
0
0
export 和 module.export 的区别

在浏览器端 js 里面,为了解决各模块变量冲突等问题,往往借助于 js 的闭包把左右模块相关的代码都包装在一个匿名函数里。而 Nodejs 编写模块相当的自由,开发者只需要关注 require,exports,...

孟飞阳
25分钟前
1
0
技术教育的兴起

技术教育的兴起 作者: 阮一峰 1、 有一年,我在台湾环岛旅行。 花莲的海边,我遇到一对台湾青年夫妻,带着女儿在海滩上玩。我们聊了起来。 当时,我还在高校当老师。他们问我,是否觉得台湾...

吕伯文
25分钟前
0
0
Linux服务器下的HTTP抓包分析

说到抓包分析,最简单的办法莫过于在客户端直接安装一个Wireshark或者Fiddler了,但是有时候由于客户端开发人员(可能是第三方)知识欠缺或者其它一些原因,无法顺利的在客户端进行抓包分析,...

mylxsw
29分钟前
0
0
mybatis3-javaapi

sqlSessionFactoryBuilder->sqlSessionFactory->sqlSession<-rowbound<-resultHandler myBatis uses a Java enumeration wrapper for transaction isolation levels, called TransactionIsol......

writeademo
33分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部