Perl正则表达式讲解

所需积分/C币:46 2013-11-01 09:10:44 948KB PDF
34
收藏 收藏
举报

Perl正则表达式讲解_摘自Perl编程详解.pdf
打印所有包含 error字符串的行 if (grep(pattern/, @lines)) print the variable \@lines has pattern in it!\n 打印所有包含模式 pattern内容的行,这直接引入下一原则 9.3.2原则2 正则表达式仅在标量上匹配 注意这里标量的重要性,如果读者试一试如下代码: CarrayName = variablel','variable2) earrayName- m/variable/:# looks for variable in the array? No use grep instead 那么@ arrayName匹軋不成功!@ array Name被Per1解释为2,于是这意味着读者在输入: 2’=°m/ variable/; 至少讲这不能给岀预想的结果。如果读者想这样做,输人为 grep(m/variable/, @arrayName) 该函数通过@ array Name中的每一个元素进行循环,返回(在标量环境中)匹配的次效,同 时在数组环境中返回匹配元素的实际列表 9.3.3原则3 对」给定的模式串,正则表达式只匹配最早岀现的匹酉项。匹配时缺省一次只匹配或替 换一次 这个原则使用称为“回溯”的过程指出如何匹配一个给定的字符串;如果发现了一个局 部匹配进而找到使该匹配无效的东西,则表达式在字符串中“回溯”最小的可能数量,这 个数量的字符要保证不丢失任何匹配。 对于理解止则衣达式止在做什么,这个原则是最有帮助的个,同时不需要与Per样 的形式来理解它正在做什么。假定有如下模式 Silly people do silly things if in silly moods 同时想匹配如下模式: silly mood 那么正则表达式引擎匹配si1ly,接着遇到 people的P,至此,正则表达式引擎知道第 个 silly不匹配,于是正则表达式引擎移到P且继续寻求匹配。它接着遇到第二个 silly, 于是来匹配 moods。然而得到的是字母t(在 thing中),于是移到 things中的t处,继续 进行匹軋。当引擎遇到第三个 silly并且尽力匹配 moods时,匹軋成功,匹配最后完成。所 发生的情况如图92所示。 当我们遇到通配符时回溯将变得更加重要。如果在同一正则表达式中有几个通配符,且 所有的通配符交织在一起,那么这里就有病态情形出现,在这种情形下,回溯变得非常昂贵。 看如下表达式 Sline expression水mat hing. *could. *be *very. *expensive. * *代表一个通配符,它意味着“匹配任意字符(换行符除外)零次或多次”。这个过程有 可能花很长时间;如果在未匹配过的字符串末尾有可能匹配,那么引擎将发狂地回溯。为得 到这方面的更多信息,请留意关于通配符方面的原则。 如果读者发现类似于上面的情形,那么通配符需将止则衣达式分解成小功部分。换句话 讲,简化自己的正则表达式。 Scalar=silly people do silly things if in silly moods: Scalar Im/silly moods/; partal match mismatch illy people do silly things if in silly mood silly me silly moo pattern slides up, backtracks to beginning. sos can match again silly people da silly things if in silly moods silly moods patem slides up, backtracks to beginning, sos can match again silly people do silly things if in silly silly panern matches fully 图9-2简单回溯 9.3.4原则4 正则表达式能够处理双引号字符串所能处理的任意和全部的字符。 在s//运算符(s/*/),或者m//运算符m/*/的第一个分隔区,位于其中的条目确实能 像双引号宇符串一样对待(有—些额外的附加功能,名义上的特殊正则表达式字符!后面描 述)。读者可用他们进行内插 Variable- TEST /s) aha/ 和 variable] aha 者都指向同一字符串:前者在Sa中匹配字符串 TESTaha.后者把$a设置为字符串 TESTaha。因为正则表达式处理双引号字符肀能处理的每个字符,所以可以执行下列操作: Sexpression ='hello Array Name elem Variable =m/expression/; this equals m/hello/ 在这里,我们简单地扣 Sexpression扩展为 hello而得到m/ hello/。这个技巧也可用于 数组: Variable=m/@arrayName / this equals myeleml elem2 在这里,表达式等价于m/ clem clem2/。如果特殊变量S"被设置为.则表达式将等价 于m/ elem elem2/,止如我们看到的,它匹配字符串的elem或者elem2。这种方法也可 应用于特殊字符 variable x01\27/; match binary character x01, and t octal character 27 &variable =s/t\tt//: substitute three tabs for three spaces. 实际上,这甲所讨论的除极少数例外以外,Per1处理在m//中的过程的确像处理在双引 中的一样。但是有例外:有某些对正则表达式引擎有明确意义的字符。那么,如果想匹配 类似于正斜杠(或者园括引()这样的字符会发生什么呢?这些字符对正则表达式引取有 特殊意义:因而不能使用如下语句: Variable= m//usr/local/ bin/; matches /usr/local/bin? NO! SYNTAX ERROR 因为Perl将把/解释为正则表达式的结束标记。这里有三种方法去匹配类似于上述特殊 字符的方法。第一种方法是利用反料杠来“转义”想匹配的任意特姝字符一包括反斜杠。因 而刚才给出的例子可变为 Spath =m/\/usr\/local\/bin/ 该程序尽力匹配$path中的/usr/ local/bin。第种方法是使用一个不同的正则表达式 字符。如果有许多字符要匹配,那么使用反斜杠则会变得很难看(路径字符尤其不好)。 幸运的是,Per1以一种合成形式来确决这个问题。因为在当读者输入m//或S//(时需要 给每个/加反斜札,所以正则表达式允许读者将正则表达式的定界符(改为自己喜欢的任意 字符。例如,我们可以使用双引号(")来避免大量的反斜杠 variable= m/usr/local/bin: Note the quotation marks variable m\"help\ If you are going to match quotation marks, you need to backslash them here. (as per\") Variable =S"$variablevariable": works in s///te 出于好的初衷,我们在本书的前几章使用了这一约定。如果使用"作为读者的正则表达式 字符,那么在用起来时它充当了好的记忆法,记住在这里所处理的实际上是字符串的变相反 插入;否则,引号就远不如斜杠常用 Per1允许使用{Q[来书写正则表达式: Variable =mithis works well with vi or emacs because the parens bounce m(this also works well) variable= s(substitute pattern) for this pattern sg 这一原则对我们处理多行正则表达式非常方便。因为在这里可以不用圆括号,所以读者 可以开始把表达式作为“微型函数”对待(如果读者有像 ema. s或v这样的合理的智能编辑 器),换句话讲,读者可在表达式的廾始和结尾部分之间往返。 第三种方法是利用函数 quotemeta(来自动地加反斜杠。如果输入如下代码 Variable=m $ scalar 则$ scalar将为被插且被转变为标量的值。这里有一个警告:任何一个特殊字符都将被 正则表达式引擎影响,并且可能引起语法错误。因此,如果标量为 scalar ({"; 那么输入如下代码: variabie=m scalar 就等价于是说: Variable=m"({",而这是一个运行时语法错误。如果表达式为如下 形式: scalar quotemeta(([): 则衣达式会使$ scalar变为\(\{,且把$ scalar替换为: svariable-m\(\ 这样才可以匹靴到读者愿意匹軋的字符串({。 9.3.5原则5 正则表达式在求值的过稈中产生两种情况:结果状态和反向引用 每次对正则表达式求值时会得到 指示正则表达式匹配字符串的次数(结果状态)。 如果希望保存部分匹配,则有一系列称为反向引用的变量。 接下来让我们依次学习他们 1.结果状态 结果状态表示正则表达式匹配字符的次数。得到结果状念的方法是在标量环境下求正则 表达式的值。以下所有例子使用了这一结果变量 pattern=’ simple always simple’; Result =(Pattern =simple 这里, result为1,因为模式 simple位于 simple always simPle中。同样的,给定 simple Result =(pattern =m"complex") 将使 result为空,因为 complex不是 simple always simple的」字符串,接着: Result =(pattern =s" simple"complex") 使 result为1,因为把 simple替换为 complex成功了。更进一步: Spat simple simple Result =(Pattern simple" complex" g) 情况变得更复杂。在这里,$ result为2,因为在 simple always simple中 simple出现 两次,同时正则表达式的g修饰符被使用,这意味着“匹配尽可能多的次数”。(要更详细材 料参看本章后面的修饰符)。同样地: pattern simple still if (pattern =m simple") print MATCHED!\n 在if子句中使用$ pattern=m" simple",而该子句基本上告诉Perl,如果模式$ pattern 包含有子串 simple则打印 Matched! 2.反向引用 反向引用有点复杂。假定想保存一些匹配供后用,那么为达到该目的,Per1有一个运算 符(圆括号(),该运算符可用于包围读者希望匹配的一系列给定的字符。 在正则表达式中用圆括号括住某模式就是告诉解释器“嗨,我希望保存那个数据。” Perl解释器再应请求,且将查找到的匹配保存在一系列特珠的变量中($1,$2,$3…·$65536) 这些变量可用来査询第一个、第二个、第三个等等圆括号匹配,这些变量于是可以通过查看 相应的变量或在数组环境下对正则表达式进行求值而且进行访问。例如: Stext this matches THIs’not’THAT text =m..) print $1\n 在这里,字柳HS被打印出来—Per1已经将它们保存在$1中,以后再打印S1。然 而,该例了揭示了更多内容,例如: 1)通配符(字符点(.)匹配任意字符)。如果THIS不在字符串中,模式(TH..)将欣然匹配 THAT。 2)正则表达式匹配一行上出现的第一处模式。THIS因为首先出现,所以被匹配。同时, 按缺省 regexp行为,THIS将总是被匹配的第一个字符串。(可以用修饰符改变缺省值,详细 情况稍后介绍)。 图9-3表示了这一匹配过程如何进行。 在图9-3中每个圆括号与自己的数字变量一道运行。 Stext="this matches"THIS andTHAT". Stext =mCTH.'). *CTH.)". pant sI: Stext="this matches THIS and [THATI. six=m(TH.TH”y SI="THS PE THAT Discard the string (no parentheses) 图93简单反向引用 这里有更多的例子: Stext =This is an example of backreferences; (Example, sbackreferences)=(Stext (example).*(backreferences)") 这里又用了通配符来分开两个文本字符串 Example和$ backreferences。这些字符串存 放在$1和$2中,且随后立即赋给$ example和$ backrefercences。该过程在图94中说明。 Stext="This is an example of lots of backreferences (Example, Filler, Sbackreferences)=(Stext =m(example)()(backreferences)") Stext=This is an( example pf lots of backreferences: 3Exampie; Sffier: -bacirefenences etexts urExampieis ackcferencesT xample Filler Sbackreferences =(example, of lots of,backreferences); xample=' example’; Filler=' of lots of'R Sbacketereaces ="backietGrnces'i 图94引用的直接赋值 然而应注意的是仅当文本字符串匹配时,给 Sexamp1e和$ bacbreference赋值的过程 才发生。当文本字符串不匹配时,$ example和 backreferences是空的。这里有更好的同样 的例子,该例子包含在if语句中,仅在匹配时打印$1和$2。 f (stext=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’; Stext =s"(examplar). *(back)"doesnt work print $1; $1因正则表达式匹配不成功而不能被赋值。更重要地,Perl不会告诉读者它没有给S1 赋任何值。最后一例展小了关于正则表达式的两点重要内容: 1)正则表达式是“要么全部要么什么也没有”的处理,只因为back字符串在模式内才能 匹配,所以 This is an example of backreferences 并不意味着整个表达式达到匹軋。因为 exemplar不在字符串中,因而替换失败 2)如果正则表达式失败,反向引用不能得到赋值。因此,不能肯定将打印出什么内容。 当眼踪逻辑问题时,这就是让人吃惊的原因;且经常是 Perl got cha。$1只是·个止则变量, 并且(与Perl语法相反)如果正则表达式失败则反向引用不被设置为“空白”。有人认为这是 个缺陷,然而另有人认为这是一个特色。不过,当分析下面的代码时第二点变得非常明显。 1$ bedbugs bite 2 Sa =m"(bedbug sets $1 to be bedbug. 4$b=’ this is nasty 5 Sb=m"(nasti) H does Not set $1 (nasti is not in'this is nasty') but $1 is still 7 print $1: # prints’ bedbug'. 在这种情况下,$1为字符串 bedbug,因为第5行的匹配失败!如果希望得到 nast.1,好 吧,那是自凵的问题。这和Perl化的行为可能让人不知所措。考虑的是自凵要当心 3.使用反向引用的一般构造法 如果想避免这种很平常的缺陷(读者想得到一个匹配,但是没有得到并且用前面的匹配为 替代而结束),在把反向引用赋给变量时只要应用下列三个构造法之一: 1)短路方法。核査匹配,如果匹配发生,此时且只有此时用’&&’进行赋值,例如: (SscalarName =m"(nasti)")Matched =$1: 1 2)if子句。将匹配放于if子句中,如果if子句为真,比时且只有此时才为模式赋值 if (sscalarName =m" (nasti)")$matched =$1: 1 else print"SscalarName didn't match; 3)直接赋值。因为可以直接把正则表达式赋给一个数值,所以可始终利用这一点。 (Smatchl, Smatch2)=(SscalarName =m"(regexp1)*(regexp2)") 读者的所有模式的匹配代码看起来应该与前述三个例子中的一个相似。缺少这些形式, 那么就是在没有安全保证的条件下进行编码。如果读者从不想有这种类型的错误的话,那么 这些形式将节省读者的大量时间。 4.在正则表达式中使用反向引用 当希望使用s"″"运算符或者用m""运算符对一些复杂模式进行匹配很难时,Perl 提供了读者应意识到的有用功能。这个功能就是反向引用可以用于正则表达式自身。换句话 说,如果用圆括号括住一组字符,那么就可以在正则表达式结束之前使用反向引用。如果想 在s"″"的第二部分(带下划线)中使用反向引用,那么要使用语法$1,S2等。如果想在m" 或者s"″"的第一部分(带下划线)使用反向引用,那么使用语法\1\2等。下面是一些例子 string=’ far out’; Sstring =s"(far)(out)"$2 $1 This makes string out fa 我们在该例中只是将单词 far out转换为 out far。 Sstring sample examples; if (Sstring =m"(amp .)ex\1") print MATCHES! \n": J 这个例子有点复杂。第一个模式(amp..)匹配字符串 ample。这意味转整个模式成为字符 串 ample example,其中带下划线的文本对应于\1。因此,模式匹配的是 sample examples 下面是同样风格更复杂的例子; Sstring bballball Sstring=s"(b)\l(a,)\1\2"$1$2″ 让我们详细地看看这个例子。该例完成匹軋,但是原因不是太明显。对这个字符串的匹 配有五个步骤: 1)在圆括号中的第个b匹配字符串的开头,接着将其仔放在\1和$1中。 2)\1于是匹配字符串中的第二个b,因为与b相等,而第二个字符碰巧是b。 3)(a..)匹配字符串a11且被存在\2和$2中。 4)1匹下一个b。 5)因为\2等于a11所以匹配下一个且是最后三个字符(a11)。 将他们放到起就得到止则表达式匹配 bba lba,或者说是整个字符串。既然$1等于 b3,$2等于a11,则整个表达式: $ string=’ bballball $ string=s"(b)\l(a..)\\2"$1$2"; (在这个例子中)转换为如下代码: Sstring s"()b(all)ball" ball 或者用行话讲,用 bballba11替换bal1。 正则表达式看起米很像图95所示。 I Sstring='bballball Sstring =-s"(b)1(a.)112"$1$2" I balban ba贴a SI=b ="db)ⅥI(a川12 (b(a.)12 bballbal b)1(a则Nv bballball e'b'H bballball t{N92 (bl(a.)\122 1= m〕 string =8"(b)\1 (a. \112"$1$2" 〔stin=s"ba) orally(bal Sstring=-s"bballball"ball") suing ba’ 图95正则表达式例子 s"""中有一些复杂的反向引用。如果理解了最后一个例子。那么读者在理解Perl的 则表达式如何工作方面远远走在了前面。反向引用可能而且确实会变得更糟。 5.嵌套反向引用 嵌套反向引用对于复杂的难以用单一顺序(一个字符串跟在另一个字符串后面)进行匹配 的字符串作用明显。例如下面的表达式: 使用*来匹忾多次出现的aa:即匹酉",aa,aa, adaaaadad。换句话说,Per1匹酉 行中有多个3a的模式。但是这个模式不会匹配aa。假定想兀配如下的字符串: Sstring softly slowly surely subtly 那么使用袄套园括号后下面的正则表达式会匹配: sstring =m"((s,. ly\s*)*)# note nested paren 在该例中,最外层的圆括号捕获全部字符串: softly s1 owly surely subtly。最内层 的圆括号捕获字符串的组合,这种组合是以s开头,以1y结尾且1y后跟空格形成的。因此 正则表达式先捕获 surely,将其抛开,然后捕获sloκly,将其抛开,然后捕荻 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..1ys米)*成为$1,(s..1ys米)*成为$2。 注意这里有另个问题。让我们起返回到网开始的复杂的止则表达式: Sstring =softly slowly surely subtly sstring =m"(((s.. ly\s*)* note nested parens 这里(s.ys*)*匹配什么呢?它匹配多个字符串;首先是 softly,接着是 slow ly,再 接着是 surely,最后是 subtly。既然(s..ly\s*)*兀配多个字符串,那么Perl会抛弃掉第 个匹配而使$2成为 subtly 即便有这些规则,嵌套圆括号仍然可能引起混乱。要做的最好事情就是实践。再一次用 这些逻辑的不同组合去实现正则表达式,然后把它们交给Per1解释器。这样做可让读者明白 反向引用是以什么次序被Perl解释器进行解释的。 9.3.6原则6 正则表达式的能力的核心在于通配符和多重匹配运算符。通配符运算符允许匹配字符串 中的多个字符。如果正在处理二进制数据,那么通配符就匹配一系列字符。多重匹配运算符 可匹配零个、个或多个字符。就讲解Perl的基础而言,到目前为止我们所使用的例了都

...展开详情
试读 28P Perl正则表达式讲解
立即下载 身份认证VIP会员低至7折
一个资源只可评论一次,评论内容不能少于5个字
您会向同学/朋友/同事推荐我们的CSDN下载吗?
谢谢参与!您的真实评价是我们改进的动力~
  • 分享学徒

关注 私信
上传资源赚钱or赚积分
最新推荐
Perl正则表达式讲解 46积分/C币 立即下载
1/28
Perl正则表达式讲解第1页
Perl正则表达式讲解第2页
Perl正则表达式讲解第3页
Perl正则表达式讲解第4页
Perl正则表达式讲解第5页
Perl正则表达式讲解第6页

试读结束, 可继续读3页

46积分/C币 立即下载