设为首页 收藏本站
查看: 787|回复: 0

[经验分享] 正则表达式之二:与正则表达式进行匹配-正则表达式与Perl接轨

[复制链接]

尚未签到

发表于 2015-12-27 11:43:08 | 显示全部楼层 |阅读模式
1、以m//进行匹配
//的编写模式是m//操作符的简写。
例:m(fred)=m<fred>=m{fred}=m[fred]=m/fred/=/fred/
批注:但只有//可以省略m
例:/^http:\/\//=m%^http://%
批注:匹配http://,常见的定界符也有用花括号的
2、可选修饰符
可有可无的修饰字符,有时候称为开关。它们可以成组附加在某个正则表达式结尾的定界符的右边,并改变正则表达式的默认行为。
一个模式里使用多个修饰符,可以写在一起,不分先后顺序。
/i:不区分大小写的匹配
例:/yes/i
批注:匹配Yes,yes,YES等等
/s:匹配任意字符,如点号(.)不匹配换行符,但加上/s后效果等于[\d\D]
/x:加入空白,在模式里随意加上空白,使更容易阅读、理解。
例:/-?\d\.?\d*/=/-? \d \.? \d* /x
例:/barney.*fred/is = /barney .* fred/isx
批注:这样加入空白后,阅读更清楚些。但加上/s后模式里面原始的空白与制表符就失去意义,它们会被忽略掉,如果想要匹配的话,可以在前面加上反斜线转义符\,不过\s(或\s*、或\s+)还是比较常用的用来匹配空白的写法。若要匹配#时,可以写成\#或[#]。另注释里不要把定界符也写进去,不然会被视为模式的终点。
3、定位
(1)字符匹配的定位
^用来标识字符串的开头
例:/^fred/    #只匹配位于字符串最前端的fred,如果是manfred mann这个字符串,则不匹配
$用来标识字符串的结尾
例:/rock$/   
批注:只匹配位于字符串最后面的rock,如果是knute rockne,则不匹配
例:/^(fred|barney)/  
批注:其中的括号很重要,现在的意思是在每行开头寻找fredbarney,若没有圆括号,就会变成在字符串的开头匹配fred或者在字符串的任何地方匹配barney
两个字符定位一起使用,可确保模式可以匹配整个字符串。
例:/^\s*$/
批注:用来匹配空白行,对所有的空白行来说等效。如果不在前后加上两个定位,则会把非空白行也一起算进去。
(2)单词定位
\b是单词边界定位,它匹配任何单词的首尾。如/\bfred\b/可匹配fred,但无法匹配frederickalfredmanfredmann。这称为整词搜索模式。此处所说的单词是指一连串字母、数字与下划线的组合,也就是匹配/\w+/模式的字符串。
例:That's a &quot;word&quot; boundary!
批注:该句子共5个单词:Thatsawordboundary。要注意的是word两边的引号并不会改变单词边界。这些单词是由一组\w字符构成的。
单词定位很有用,不会使我们意外地在delicatessen中找到cat,在boondoggle中找到dog或在selfishness中找到fish。也可以只用到一个单词边界定位。如
/\bhunt/匹配hunthuntinghunter,而排除了shunt;用/stone\b/匹配standstoneflintstone,但不包括capstones
4、绑定操作符
=~默认的情况下模式匹配的对象是$_,绑定操作符=~能让Perl拿右边的模式来匹配左边的字符串,而非匹配$_。虽然它看起来像某种赋值运算,但并不是。它指的是本来这个模式会匹配$_变量,但请针对左边的字符串匹配吧。若没有绑定操作符,表达式就会使用默认的$_。
my $some_other = &quot;I dream of betty rubble.&quot;;
if($some_other =~/\brub/){
print &quot;Aye, there's the rub.\n&quot;;}
在下面这个(不寻常的)例子里,$likes_perl会被赋予一个布尔值,这个结果取决于用户键入的内容。这个程序属于“急功近利”型的,因为判断后就丢弃了用户的输入。这行代码大致上的功能是读取输入行,匹配字符串与模式,然后舍弃输入行的内容。没有进一步使用$_,也没有改变它。

print &quot;Do you like Perl?&quot;;
my $likes_perl = (<STDIN> =~ /\byes\b/i);
……  #耗时的其它程序……
if($likes_perl){
print &quot;You said earlier that you like Perl,so..\n&quot;;}
批注:除非while循环的条件表达式中只有整行输入操作符(<STDIN>),否则输入行不会自动存入$_。因为绑定操作符的优先级相当高,也就没必要用圆括号来跨住模式测试表达式。所以下面这一行如同上面的表达式一样,会将匹配结果(而非输入的内容)存进变量。my $likes_perl = <STDIN> =~ /\byes\b/i;
5、模式串中的内插

#!/usr/bin/perl -w
my $what = &quot;larry&quot;;
while(<>){
if(/^($what)/){
print &quot;We saw $what in beginning of $_&quot;;}}
批注:不管$what的内容是什么,当我们进行模式匹配的时候,该模式都会成为$what的值。在这里它和/^(larry)/是相同的意思,也就是在每行的开头寻找larry
6、模式中变量的存储
(1)捕获变量
匹配变量(包括自动匹配变量和带编号的匹配变量)最常用在替换运算中。圆括号同时也启动了正则表达式处理引擎的捕获功能。即把(圆括号中模式所匹配的)部分字符串暂时记下来的能力。如果有一对以上的圆括号,就会有一次以上的捕获。
每个被捕获的对象是原本的字符串,而不是模式。因为捕获变量存储的都是字符串,所以它们都是标量变量。在Perl里,它们的名字类似$1或者$2。模式里的括号有多少对,匹配变量就有多少个。如$4就是第四对括号捕获的字符串。这些变量能够取出字符串里的某些部分,因此是正则表达式威力强大的重要原因之一。

$_=&quot;Hello there,neighbor&quot;;
if(/\s(\w+),/){   #捕获空白符和逗号之间的单词
print &quot;the word was $1\n;&quot;
批注:打印the word was there
也可以一次捕获多个串。

$_=&quot;Hello there,neighbor&quot;;
if(/(\S+) (\S+), (\S+)/){   #捕获空白符和逗号之间的单词
print &quot;the word was $1 $2 $3\n;&quot;}
批注:让我们知道这些单词是Hello there neighbor。注意逗号的处理

my $dino=&quot;I fear that I'll be extinct after 1000 years.&quot;;
if($dino =~ /(\d*) years/){
print &quot;That said '$1' years.\n&quot;;   #$1为1000
my $dino=&quot;I fear that I'll be extinct after a few million years.&quot;;
if($dino =~ /(\d*) years/){
print &quot;That said '$1' years.\n&quot;;   
批注:$1为空字符串,而不是尚未定义。若模式中有三个一下的圆括号,$4才会是undef
(2)捕获变量的生命期
这些捕获变量通常能存活到下次成功的模式匹配为止。也就是说,失败的匹配不会改动上次成功匹配时捕获的内容,而成功的匹配会将它们重置。如果对比失败,它会输出可能遗留在$1里的任何字符串。

$wilma = ~ /(\w+)/;  #不对!这里的结果不一定正确
print &quot;Wilma's word was $1...or was it?\n&quot;;
批注:这就是为什么模式匹配总是出现在ifwhile条件表达式里:

if($wilma =~ /(\w+)/){
print &quot;Wilma's word was $1.\n&quot;;}
else{
print&quot;Wilma doesn't have a word.\n&quot;;}
因为捕获的内容不会永久留存,所以匹配变量只应该在模式匹配后的数行内使用。通常最好的做法是将它复制到某个一般的变量里。后面有更好的处理办法,即模式匹配发生时,直接将捕获的内容存到变量中。

if($wilma =~ /(\w+)/){
my $wilma_word = $1;...}
(3)不捕获模式
现在是每个括号的内容都会被变量捕获,也可以设置某一个括号里的内容不被捕获。

if(/(?:bronto)?saurus (steak|burger)/){
print &quot;Fred wants a $1\n&quot;;}
批注:这样增减选项的时候就不用修改捕获变量的名字了

if(/(?:bronto)?saurus (?:BBQ)?(steak|burger)/){
print &quot;Fred wants a $1\n&quot;;}
(4)命名捕捉
以上的变量捕捉方式有不好的地方。即使对于较为简单的模式来说,管理这样的数字变量也是比较困难的。如下例:

use 5.010;
my $names='Fred or Barney';
if($names=~m/(\w+) and (\w+)){ #不会匹配
say &quot;I saw $1 and $2&quot;;}
批注:不会看到say的输出,因为模式里的and和实际变量中的or不匹配。我们考虑后认为两者可以并存,加入“择一”来匹配and或者or。当然需要在模式中加入一对括号。

use 5.010;
my $names='Fred or Barney';
if($names=~m/(\w+) (and|or) (\w+)){
say &quot;I saw $1 and $2&quot;;}
批注:现在可以匹配了,但由于第二个括号的引入,是$2变量中的内容不是我们期望的了,期望的则进入了$3。打印输出I saw Fred and or,当然可以改为(?:and|or),但还是不方便。
Perl5.10引入了正则表达式命名捕捉的概念。现在捕捉的结果会进入一个特殊的哈希%+,其中的键就是在捕捉时候使用的特殊标签,其中的值就是被捕捉的串。为捕捉串加标签的方法是使用(?<LABEL>PATTERN)这样的写法,而LABEL可以自行命名。

use 5.010;
my $names = 'Fred or Barney';
if($names =~ m/(?<name1>\w+)) (?:and|or) (?<name2>\w+){
say &quot;I saw $+{name1} and $+{name2}&quot;;}
批注:现在就能看到正确的结果:I saw Fred and Barney
一旦使用了捕捉标签,就可以随意移动位置并加入更多的捕获括号,不会因为括号的次序变化导致麻烦。

use 5.010;
my $names = 'Fred or Barney';
if($names =~ m/((?<name1>\w+)) (?:and|or) (?<name2>\w+)){
say &quot;I saw $+{name1} and $+{name2}&quot;;}
批注:在使用捕捉标签之后,也给反向引用带来了更新的必要。之前我们使用\1或者g{1}这样的写法,现在我们可以使用\g{label}这样的写法。另外一种表示\k<lable>=\g{label}。

use 5.010;
my $names = 'Fred Flinstone and Wilma Flinstone';
if($names =~ m/(?<last_name>\w+) and \w+ \g{last_name}/){
say &quot;I saw $+{last_name}&quot;;}
(5)自动匹配变量
自动匹配变量有可能是空字符串,它们的有效范围也与标号的匹配变量相同。一般情况下,它们的值会一直持续到下一次模式匹配成功之前。
自动匹配变量会拖慢其它正则表达式的运行速度,所以一般很少使用它们。
$&:字符串里实际匹配模式的部分会自动存进$&里。

if(&quot;Hello there, neighbor&quot; =~ /\s(\w+),/){
print &quot;That actually matched '$&'.\n&quot;;}
批注:$&里匹配的部分是“ there,”(一个空格,一个单词及一个逗号),相比之下,$1存储的则只有单词there,但$&里有整个的匹配段落。
$`:存储匹配起始位置之前的字符串(保存了正则表达式引擎在找到匹配段落之前略过的部分)。
$':存储匹配结束位置之后的字符串(保存了字符串中剩下的,从来没有匹配到的部分)。
如果将这三个字符串依此连接起来,就一定会得到原来的字符串。

if(&quot;Hello there, neighbor&quot; =~ /\s(\w+),/){
print &quot;That was ($`)($&)($').\n&quot;;}
批注:会输出(Hello)(there,)(neighbor)
7、通用量词:花括号量词
/a{5,15}/:匹配重复出现515次的字母a
/a{5,}/:至少5次,没有上限,a之间不能有空格等额外符号
/a{8}/:匹配正好8个字符的单词串
/,{5}chameleon/:匹配,,,,,chameleon
*={0,} +={1,} ?={0,1}
8、优先级
优先级告诉我们模式中哪些部分的紧密度最高。正则表达式的优先级只有4个级别。
优先级顶端的是(?),用来分组和捕获。
第二级是量词,也就是重复操作符:星号(*)、加号(+)、问好(?)以及花括号量词,像{5,15}、{3,}、{5}等。
第三极是定位与序列。定位包括:定位开头^,定位结尾$,词边界\b,非词边界\B。单词里的字母之间和定位与字母之间的紧密程度是相同的。
最低的是“择一”竖线(|)。因为是最低一级,它实际上会将模式拆分成数个部分。
完全没有优先级的就是那些组成模式的基本元素。包括每个独立的字符,字符集和反向引用。
例:/^fred|barney$/
批注:要么匹配字符串开头的fred,要么匹配字符串结尾的barney
例:/^(fred|barney)$/
批注匹配只包含fred或是只包含barney的每一行。
例:/(wilma|pibbles?)/
批注:匹配willmapebbles一级pebble这三个字符串,或是长字符串的一部分(因为模式中没有定位)。
例:/^(\w+)\s+(\w+)$/
批注:匹配开始是一个单词,再来一些空白,然后又是一个单词的行。如fred flintstone之类的字符串。这里的圆括号并不是为了分组而存在,可能只是为了把匹配的字符串给捕获下来。
在尝试理解一个很复杂的模式时,试着加上一些括号会对弄清楚优先级有好处。但请记住,圆括号同时也会有捕获的效果。因此建议尽可能用非捕获的圆括号来分组。
(9)模式测试程序
下面是一个有用的程序,可用来检测某些字符串是否能被指定的模式匹配。

#!/usr/bin/perl
while(<>){
chomp;
if(/YOUR_PATTERN_GOES_HERE/){
print &quot;Matched: |$`<$&>$'|\n&quot;;}
else{
print &quot;No match: |$_|\n&quot;;}

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-156907-1-1.html 上篇帖子: 【转】perl中的grep函数介绍 下篇帖子: summarize perl
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表