以可以作为if或while等的条件语句。例如,改为while循环多次匹配:
默认全局匹配情况下,当本次匹配失败,位移指针将重置到起始位置0处,也就是说,下次匹配将从头开始匹配。例如:
执行上述程序,将输出:
如果"g"修饰符下同时使用"c"修饰符,也就是"gc",它表示全局匹配失败的时候不重置位移指针。也就是说,本次匹配失败后,位移指针会向后移一位,下次匹配将从后移的这个位置处开始匹配。当位移移到了结尾,将无法再移动,此时位移指针将一直指向最后一个位置。
执行上述程序,将输出:
继续上面的问题,如果第三个匹配语句不是\d\d\d
,而是"\d",它匹配字母a的时候也失败,不用c修饰符的时候会重置位移吗?显然是不会。因为它会继续向后匹配。所以该\G
登场了。
默认全局匹配情况下,匹配时是可以跳过匹配失败的字符继续匹配的:当某个字符匹配失败,它会后移一位继续去匹配,直到匹配成功或匹配结束。
执行上述程序,将输出:
可以指定\G
,使得本次匹配强制从位移处进行匹配,不允许跳过任何匹配失败的字符。
例如:
以下是输出内容:
如果将上面第三个匹配语句加上修饰符c,甚至后面的语句也都加上\G
和c修饰符,那么位移指针将卡在那个位置:
以下是输出结果:
一般来说,全局匹配都会用循环去多次迭代,和上面一次一次列出匹配表达式不一样。所以,下面使用while循环的例子来对\G
和c修饰符稍作解释,其实理解了上面的内容,在循环中使用\G
和c修饰符也一样很容易理解。
执行结果:
当第三轮循环匹配到a字母的时候,由于使用了\G
,导致匹配失败,结束循环。
上面使用c与否是无关紧要的,但如果这个while循环的后面后还有对$txt
的匹配,那么使用c修饰符与否就有关系了。例如下面两段程序,返回结果不一样:
和
正则表达式一般都只用来匹配单行数据,但有时候却需要一次性匹配多行。比如匹配跨行单词、匹配跨行词组,匹配跨行的对称分隔符(如一对括号)。
使用m修饰符可以开启多行匹配模式。
例如:
执行,将输出:
关于多行匹配,需要注意的是元字符.
默认情况下无法匹配换行符。可以使用[\d\D]
代替点,也可以开启s修饰符使得.
能匹配换行符。
例如,下面两个匹配输出的结果和上面是一致的。
默认情况下,.
元字符是不能匹配换行符\n
的,开启了s修饰符功能后,可以让.
匹配换行符。正如刚才的那个例子:
正则表达式最为人所抱怨的就是它的可读性极差,无论你的正则能力有多强,看着一大堆乱七八糟的符号组合在一起,都得一个符号一个符号地从左向右读。
万幸,perl正则支持表达式的分隔,甚至支持注释,只需加上x修饰符即可。这时候正则表达式中出现的所有空白符号都不会当作正则的匹配对象,而是直接被忽略。如果想要匹配空白符号,可以使用\s
表示,或者将空格使用\Q...\E
包围。
例如,以下4个匹配操作是完全等价的。
对于稍微复杂一些的正则表达式,常常都会使用x修饰符来增强其可读性,最重要的是加上注释。这一点真的非常人性化。
前面说过,通过3个特殊变量$`
、$&
和$'
可以保存匹配内容之前的内容,匹配内容以及匹配内容之后的内容。但是,只要使用了这3个变量中的任何一个,后面的所有分组效率都会降低。perl提供了一个p修饰符,能实现完全相同的功能:
一个例子即可描述:
在较老的perl版本中,如果使用同一个正则表达式做多次匹配,正则引擎将只多次编译正则表达式。很多时候正则表达式并不会改变,比如循环匹配文件中的行,这样的多次编译导致性能下降很明显,于是可以使用o修饰符让正则引擎对同一个正则表达式不重复编译。
在perl5.6中,默认情况下对同一正则表达式只编译一次,但同样可以指定o修饰符,使得即使正则表达式变化了也不要重新编译。
一般情况下,可以无视这个修饰符。
前文介绍的修饰符adluoimsxpngc
都是放在m//{FLAG}
的flag处的,放在这个位置会对整个正则表达式产生影响,所以它的作用范围有点广。
例如m/pattern1 pattern2/i
的i修饰符会影响pattern1和pattern2。
perl允许我们定义只在一定范围内生效的修饰符,方式是(?imsx:pattern)
或(?-imsx:pattern)
或(?imsx-imsx:pattern)
,其中加上-
表示去除这个修饰符的影响。这里只列出了imsx,因为这几个最常用,其他的修饰符也一样有效。
例如,对于待匹配字符串"Hello world gaoxiaofang",使用以下几种模式去匹配的话:
/(?i:hello) world/
表示匹配hello时,可忽略大小写,但匹配world时仍然区分大小写。所以匹配成功
/(?ims:hello.)world/
表示可以跨行匹配helloworld,也可以匹配单行的hellosworld,且hello部分忽略大小写。所以匹配成功
/(?i:hello (?-i:world) gaoxiaoFANG)/
表示在第二个括号之前,可用忽略大小写进行匹配,但因为第二个括号里指明了去除i的影响,所以对world的匹配会区分大小写,但是对gaoxiaofang部分的匹配又不区分大小写。所以匹配成功
/(?i:hello (?-i:world) gaoxiao)FANG/
和前面的类似,但是将"FANG"放到了括号外,意味着这部分要区分大小写。所以匹配失败
1.锚定类的反斜线序列
所谓锚定,是指它匹配的是位置,而非字符,比如锚定行首的意思是匹配第一个字母前的空字符。也就是很多人说的"零宽断言(zero-width assertions)"。
主要解释下\A \z \Z
,其它的属于基础正则的内容,不多做解释了。
\A \z \Z
和^ $
的区别主要体现在多行模式下。在多行模式下:
从上面的$
匹配示例可知,$
代表的行尾,其实它在有换行符的时候匹配"\n",而不是"\n"的前、后,在没有换行符的时候,匹配行尾。
2.字符匹配反斜线序列
当然,除了以下这几种,还有\v \V \h \H \R \p \c \X
,这些基本不会用上,所以都不会在本文解释。
由于元字符.
默认无法匹配换行符,所以需要匹配换行符的时候,可以使用特殊组合[\d\D]
或者(\n|\N)
来替换.
,换句话说,如果想匹配任意长度的任意字符,可以换成[\d\D]*
或者(\n|\N)*
,当然,前提是必须支持这3个反斜线序列。
之所以不用[\n\N]
替代元字符.
,是因为\N
有特殊意义,不能随意接符号和字母。
3.分组引用的反斜线序列
\1
表示引用第一个分组,\11
表示引用第11个分组,在基础正则中,是不支持引用超出9个分组的,但显然perl会将\11
的第二个1解析为引用,以便能引用更多分组。
同理\g1
和\g11
,只是使用\g
引用的方式可以加上大括号使引用变得更安全,更易读,且\g
可以使用负数来表示从右向左相对引用。这样在\g{-2}
的左边添加新的分组括号时,无须修改引用表达式。
此处暂时还没介绍到命名分组,所以\g{name}
和\k<name>
留在后面再介绍。
\K
表示强制中断前面已完成的匹配。例如"abc22ABC" =~ /abc\K2.*/;
,虽然abc三个字母也被