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

[经验分享] Perl正则表达式讲解

[复制链接]

尚未签到

发表于 2018-8-31 10:54:46 | 显示全部楼层 |阅读模式
2.反向引用反向引用有点复杂。假定想保存一些匹配供后用,那么为达到该目的,Perl有一个运算符(圆括号()),该运算符可用于包围读者希望匹配的一系列给定的字符。  在正则表达式中用圆括号括住某模式就是告诉解释器“嗨,我希望保存那个数据。” Perl解释器再应请求,且将查找到的匹配保存在一系列特珠的变量中($1,$2,$3…$65536),这些变量可用来查询第一个、第二个、第三个等等圆括号匹配,这些变量于是可以通过查看相应的变量或在数组环境下对正则表达式进行求值而且进行访问。例如:
  $text = " this matches ' THIS' not 'THAT' ";
  $text =~ m" ('TH..' )";
  print " $1\n";
  在这里,字柳HIS被打印出来 —— Perl已经将它们保存在$1中,以后再打印$1。 然而,该例子揭示了更多内容,例如:
  1)通配符(字符点(.)匹配任意字符)。如果THIS不在字符串中,模式(TH..)将欣然匹配
  THAT。
  2)正则表达式匹配一行上出现的第一处模式。THIS因为首先出现,所以被匹配。同时,按缺省regexp行为,THIS将总是被匹配的第一个字符串。(可以用修饰符改变缺省值,详细情况稍后介绍)。
  图 9-3 表示了这一匹配过程如何进行。
  在图 9-3 中每个圆括号与自已的数字变量一道运行。
  这里有更多的例子:
  $text = ' This is an example of backreferences';
  ($example, $backreferences) = ($text =~ m" (example).*(backreferences)" );
  这里又用了通配符来分开两个文本字符串$example和$backreferences。这些字符串存放在$1和$2中,且随后立即赋给$example和$backrefercences。该过程在图9—4中说明。
  然而应注意的是仅当文本字符串匹配时,给$example和$bacbreference赋值的过程才发生。当文本字符串不匹配时,$example和 backreferences是空的。这里有更好的同样的例子,该例子包含在if语句中,仅在匹配时打印$1和$2。
  if ($text =~ m" (example).*(back)")
  {
  print $1; # prints ' example' -- since the first parens match the text example.
  print $2; # prints ' back' -- since the second parens match the text back
  }
  这样,如果正则表达式根本不匹配将发生什么?如果使用下面的模式:
  $text = ' This is an example of backreferences';
  $text =~ s" (examplar).*(back)" doesn't work";
  print $1;
  $1因正则表达式匹配不成功而不能被赋值。更重要地,Perl不会告诉读者它没有给$1赋任 何值。最后一例展示了关于正则表达式的两点重耍内容:
  1)正则表达式是“要么全部要么什么也没有”的处理,只因为back字符串在模式内才能匹 配,所以:
  This is an example of backreferences'
  并不意味着整个表达式达到匹配。因为exemplar不在字符串中,因而替换失败。
  2)如果正则表达式失败,反向引用不能得到赋值。因此,不能肯定将打印出什么内容。当跟踪逻辑问题时,这就是让人吃惊的原因;且经常是Perl gotcha。$1只是一个正则变量,并且(与Perl语法相反)如果正则表达式失败则反向引用不被设置为“空白”。有人认为这是一个缺陷,然而另有人认为这是一个特色。不过,当分析下面的代码时第二点变得非常明显。
  1 $a = ' bedbugs bite';
  2 $a =~ m" (bedbug)"; # sets $1 to be bedbug.
  3
  4 $b = ' this is nasty';
  5 $b =~ m" (nasti)"; # does NOT set $1 (nasti is not in ' this is nasty' ).
  6 # BUT $1 is still set to bedbug!
  7 print $1; # prints ' bedbug'.
  在这种情况下,$1为字符串bedbug,因为第5行的匹配失败!如果希望得到nasti,好吧,那是自己的问题。这种Perl化的行为可能让人不知所措。考虑的是自己要当心。
  3.使用反向引用的一般构造法
  如果想避免这种很平常的缺陷(读者想得到一个匹配,但是没有得到并且用前面的匹配为 替代而结束),在把反向引用赋给变量时只要应用下列三个构造法之一:
  1)短路方法。核查匹配,如果匹配发生,此时且只有此时用' &&'进行赋值,例如:
  ($scalarName =~ m" (nasti)" ) {$matched = $1;}
  2)if子句。将匹配放于if子句中,如果if子句为真,此时且只有此时才为模式赋值。
  if ($scalarName =~ m" (nasti)" ) {$matched = $1;}
  else {print "$scalarName didn't match"; }
  3)直接赋值。因为可以直接把正则表达式赋给一个数值,所以可始终利用这一点。
  ($match1, $match2) = ($scalarName =~ m" (regexp1).*(regexp2)" );
  读者的所有模式的匹配代码看起来应该与前述三个例子中的一个相似。缺少这些形式,那么就是在没有安全保证的条件下进行编码。如果读者从不想有这种类型的错误的话,那么这些形式将节省读者的大量时间。
  4.在正则表达式中使用反向引用
  当希望使用s" " "运算符或者用m" "运算符对一些复杂模式进行匹配很困难时,Perl提供了读者应意识到的有用功能。这个功能就是反向引用可以用于正则表达式自身。换句话说,如果用圆括号括住一组字符,那么就可以在正则表达式结束之前使用反向引用。如果想在s" " "的第二部分(带下划线)中使用反向引用,那么要使用语法$1,$2等。如果想在m" "或者s" " "的第一部分(带下划线)使用反向引用,那么使用语法\1\2等。下面是一些例子:
  $string = ' far out';
  $string =~ s "(far)(out)" $2 $1"; # This makes string ' out far'.
  我们在该例中只是将单词far out转换为out far。
  $string = ' sample examples';
  if ($string =~ m" (amp..) ex\1") {print " MATCHES!\n"; }
  这个例子有点复杂。第—个模式(amp..)匹配字符串ample。这意味转整个模式成为字符串ample example,其中带下划线的文本对应于\1。因此,模式匹配的是 sample examples。
  下面是同样风格更复杂的例子;
  $string = ' bballball';
  $string =~ s" (b)\1(a...)\1\2" $1$2";
  让我们详细地看看这个例子。该例完成匹配,但是原因不是太明显。对这个字符串的匹配有五个步骤:
  1)在圆括号中的第一个b匹配字符串的开头,接着将其存放在\1和$1中。
  2)\1于是匹配字符串中的第二个b,因为与b相等,而第二个字符碰巧是b。
  3)(a..)匹配字符串all且被存在\2和$2中。
  4)\1匹配下一个b。
  5)因为\2等于all所以匹配下一个且是最后三个字符(all)。
  将他们放到一起就得到正则表达式匹配bballball,或者说是整个字符串。既然$1等于' b',$2等于all,则整个表达式:
  $string = ' bballball' ;
  $string =~ s" (b)\1(a..)\1\2" $1$2";
  (在这个例子中)转换为如下代码:
  $string =~ s" (b)b(all)ball" ball";
  或者用行话讲,用bballball替换ball。 ’
  正则表达式看起来很像图 9-5 所示。
  s" " "中有一些复杂的反向引用。如果理解了最后一个例子。那么读者在理解Perl的正则表达式如何工作方面远远走在了前面。反向引用可能而且确实会变得更糟。
  5.嵌套反向引用
  嵌套反向引用对于复杂的难以用单一顺序(一个字符串跟在另一个字符串后面)进行匹配的字符串作用明显。例如下面的表达式:
  m" ((aaa)*)" ;
  使用 * 来匹配多次出现的aaa:即匹配",aaa,aaaaaa,aaaaaaaaa。换句话说,Perl匹配一行中有多个3a的模式。但是这个模式不会匹配aa。假定想匹配如下的字符串:
  $string = ' softly slowly surely subtly';
  那么使用嵌套园括号后下面的正则表达式会匹配:
  $string = m" ((s...ly\s*)*)" ; # note nested parens.
  在该例中,最外层的圆括号捕获全部字符串:softly slowly surely subtly 。最内层的圆括号捕获字符串的组合,这种组合是以s开头,以ly结尾且ly后跟空格形成的。因此,正则表达式先捕获surely,将其抛开,然后捕获 slowly,将其抛开,然后捕获surely,最后捕获subtly。这里有一个问题,反向引用按什么顺序出现?读者可能在这个问题上很容易迷惑。是外层圆括号先出现呢,还是内层的内括圆号先出现?最简单的解决办法是记住以下三条原则:
  1)在表达式中,一个反向引用越在前,它对应的反向引用编号就越小。例如:
  $var =~ m" (a)(b)";
  该例中,反向引用(a)变为$1,(b)变成了$2。
  2)一个反向引用如果它包含范围越广,则它的反向引用编号就越小。例如:
  $var =~ m" (c(a(b)*)*)";
  该例中,包含全部内容(m "(c(a(b)*)*)" )的反向引用成为$1。有a嵌套在里面的表达式 m"(c(a(b)*)*)"成为$2。在(m"(c(a(b)*)*)" )中带有b的嵌套表达式成为$3。
  3)在两个规则冲突的情况下,规则1优先。在语句$var =~ m" (a)(b(c))" 中,(a)成为$1,b(c)成为$2,(c)成为$3。
  因而,在这个例子中,(s...ly\s*)*成为$1,(s...ly\s*)*成为$2。
  注意这里有另一个问题。让我们一起返回到刚开始的复杂的正则表达式:
  $string = 'softly slowly surely subtly'
  $string = m"(((s...ly\s*)*)"; # note nested parens.
  这里(s...ly\s*)*匹配什么呢?它匹配多个字符串;首先是softly,接着是slowly,再接着是surely,最后是subtly。既然(s...ly\s*)*匹配多个字符串,那么Perl会抛弃掉第一个匹配而使$2成为subtly。
  即便有这些规则,嵌套圆括号仍然可能引起混乱。要做的最好事情就是实践。再一次用这些逻辑的不同组合去实现正则表达式,然后把它们交给Perl解释器。这样做可让读者明白反向引用是以什么次序被Perl解释器进行解释的。


运维网声明 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-559294-1-1.html 上篇帖子: perl语言入门(7) 下篇帖子: 利用perl检测系统中登陆用户相关的进程升级版
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

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

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

扫描微信二维码查看详情

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


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


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


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



合作伙伴: 青云cloud

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