设为首页 加入收藏

TOP

Perl正则表达式超详细教程(三)
2018-10-10 04:10:29 】 浏览:367
Tags:Perl 正则 表达式 详细 教程
匹配,如果没有\K,这3个字母将放进$&中,但是\K使得匹配完abc后立即切断前面的匹配,也就是从c字母后面开始重新匹配,所以这里匹配的结果是22ABC。


再例如,"abc123abcfoo"=~ /(abc)123\K\g1foo/;,它匹配到123后被切断,但是分组引用还可以继续引用,所以匹配的结果是"abcfoo"。


在基础正则中,那些能匹配多次的量词都会匹配最长内容。这种尽量多匹配的行为称为"贪婪匹配"(greedy match)。


例如字符串"aa1122ccbb",用正则表达式a.*c去匹配这个字符串,其中的.*将直接从第二个字母a开始匹配到最结尾的b,因为从第二个字母a开始到最后一个字母b都符合.*的匹配模式。再然后,去匹配字母c,但因为已经把所有字母匹配完了,只能回退一个字母一个字母地释放,每释放一个就匹配一次字母c,发现回退释放到倒数第三个字母就能满足匹配要求,于是这里的.*最终匹配的内容是"a1122c"。


上面涉及到回溯的概念,也就是将那些已经被量词匹配的内容回退释放。


上面描述的是贪婪匹配行为,还有非贪婪匹配、占有优先匹配,以下简单描述下他们的意义:


有必要搞清楚这几种匹配模式在匹配机制上的区别:


除了上面描述的*量词会进行贪婪匹配,其他所有能进行多次匹配的量词可以选择贪婪匹配模式、非贪婪匹配模式和占有优先匹配模式,只需选择对应的量词元字符即可。如下:


几点需要说明:


看以下示例即可理解贪婪和非贪婪匹配的行为:


以下是占有优先匹配模式的示例:


所以,在使用占有优先匹配模式时,它后面不应该跟其他表达式,例如a*+x永远匹配不了东西。绝大多数时候都是不会回溯的。但是少数情况下,它并非强制锁住回溯,这个和正则引擎匹配原理有关,本文不多做解释。


另外,固化分组和占有优先并不完全等价,它们只是匹配行为相同:匹配后不回溯。具体可对比后文对应内容。


在基础正则中,使用括号可以对匹配的内容进行分组,这种行为称为分组捕获。捕获后可以通过\1这种反向引用方式去引用(访问)保存在分组中的匹配结果。


例如:


在perl中,还可以使用\gN的方式来反向引用分组,这个在上一节"反斜线序列"中已经解释过了。例如,以下是和上面等价的几种写法:


perl还会把分组的内容放进perl自带的特殊变量$1,$2,...,$N中,它们和\1,\2,...\N匹配成功时的结果上没有区别,但是\N这种类型的反向引用只在正则匹配中有效,正则匹配结束后就消亡了,而$N因为是perl的变量,即使正则已经退出匹配,也依然可以引用。所以,我们可以使用$N的方式来输出分组匹配的结果:


有两点需要注意:


第一点,示例可知:


第二点,从机制上去分析。\1是每个正则匹配都相互独立的,而$1则保存分组捕获成功的值,即使这次值是上次捕获的。


这里稍微解释下正则匹配关于分组捕获的匹配过程:


例如,匹配表达式"12abc22abc" =~ /\d(abc)\d\d\1/;,当正则引擎去匹配数据时:
1.首先匹配第一个数字1,发现符合\d,于是继续用(abc)去匹配字符串,因为发现了是分组括号,于是会将第二个字符2放进分组,发现不匹配字母a,于是匹配失败,丢弃这个分组中的内容。
2.正则引擎继续向后匹配数值2,发现符合\d,于是用(abc)去匹配字符串,接着会将第三个字符a放进分组,发现能匹配,继续匹配字符串中的b、c发现都能匹配,于是分组捕获完成,将其赋值给$1,之后就能用\1$1去引用这个分组的内容。
3.后面继续去匹配\d\d\1,直到匹配结束。


当然,具体匹配的过程不会真的这么简单,它会有一些优化匹配方式,以上只是用逻辑去描述匹配的过程。


在perl中,支持的分组捕获更强大、更完整,它除了支持普通分组(也就是直接用括号的分组),还支持:


匿名捕获是指仅分组,不捕获。因为不捕获,所以无法使用反向引用,也不会将分组结果赋值给$1这种特殊变量。


虽然有了分组捕获功能,就可以实现任何需求,但有时候可以让这种行为变得更人性化,减少维护力度。


例如字符串"xiaofang or longshuai",使用模式/(\w+) or (\w+)/去捕获,用$1$2分别引用or左右两个单词:


但如果需求是中间的关系or也可以换成and,为了同时满足and和or两种需求,使用模式/(\w+) (and|or) (\w+)/去匹配,但是这时引用的序号就得由$2变为$3


如果使用匿名捕获,对and和or这样无关紧要,却有可能改变匹配行为的内容,可以将其放进一个无关的分组中。这样不会对原有的其余正则表达式产生任何影响:


注意上面仍然使用$2引用第三个括号。


同样,如果要在正则内部使用反向引用,也一样使用\2来引用第三个括号。


另外,在前文还介绍过一个n修饰符,它也表示非捕获仅分组行为。但它只对普通分组有效,对命名分组无效。且因为它是修饰符,它会使所有的普通分组都变成非捕获模式。


由于上面开启了n修饰符,使得3个普通分组括号都变成非捕获仅分组行为,所以\1$1都无法使用。除非正则中使用了命名分组。


命名捕获是指将捕获到的内容放进分组,这个分组是有名称的分组,所以后面可以使用分组名去引用已捕获进这个分组的内容。除此之外,和普通分组并无区别。


当要进行命名捕获时,使用(?<NAME>)的方式替代以前的分组括号()即可。例如,要匹配abc并将其分组,以前普通分组的方式是(abc),如果将其放进命名为name1的分组中:(?<name1>abc)


当使用命名捕获的时候,要在正则内部引用这个命名捕获,除了可以使用序号类的绝对引用(如\1\g1\g{1}),还可以使用以下任意一种按名称引用方式:


如果要在正则外部引用这个命名捕获,除了可以使用序号类的绝对应用(如$1),还可以使用$+{NAME}的方式。


实际上,后一种引用方式的本质是perl将命名捕获的内容放进了一个名为%+的特殊hash类型中,所以可以使用$+{NAME}的方式引用,如果你不知道这一点,那就无视与此相关的内容即可,不过都很简单,一看就懂。


例如:


其中上述代码中的\g1还可以替换为\1\g{firstname}\k{firstname}\k<firstname>


通过使用命名捕获,可以无视序号,直接使用名称即可准确引用。



首先固化分组不是一种分组,所以无法去引用它。它和"占有优先"匹配模式(贪婪匹配、惰性匹配、占有优先匹配三种匹配模式,见后文)是等价的除了这两种称呼,在不同的书、不同的语言里还有一种称呼:原子匹配。


它的表示形式类似于分组(?>),所以有些地方将其称呼为"固化分组"。再次说明,固化分组不是分组,无法进行引用。如果非要将其看作是分组,可以将其理解为被限定的匿名分组:不捕获,只分组。


如果不知道什么是回溯,看完下面的例子就明白。


例如"hello world"可以被hel.* world成功匹配,但不能被hel(?>.*) world匹配。因为正常情况下,.*匹配到所有内容,然后往回释放已匹配的内容直到释放完空格

首页 上一页 1 2 3 4 下一页 尾页 3/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇排序变换思路:施瓦茨变换 下一篇Perl正则表达式引用

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目