perl正则表达式
perl的正则表达式有三种形式:匹配,替换和转化。
-
匹配:m//(还可以简写为//,略去m)
-
替换:s///
-
转化:tr///
这三种形式一般都和 =~ 或 !~ 搭配使用, =~ 表示相匹配,!~ 表示不匹配。
一.匹配
匹配操作符 m// 用于匹配一个字符串语句或者一个正则表达式,使用=~
符号表示要用右边的正则表达式对左边的数据进行匹配,匹配返回真,否则返回假,m可以省略,缩写为//。
如果想要输出匹配到的内容,可以使用特殊变量$&来引用匹配到的内容,还可以使用$`引用匹配前面部分的内容,$'引用匹配后面部分的内容。
my $str1="AbcgggBbCcbggggA"; #匹配到第一个ggg就结束 if($str1=~/ggg/) { #如果想要输出匹配到的内容,可以使用特殊变量$&来引用匹配到的内容,还可以使用$`引用匹配前面部分的内容,$'引用匹配后面部分的内容 print "匹配到的内容:$&\n"; #输出ggg print "匹配前面部分的内容:$`\n"; #输出Abc print "匹配后面部分的内容:$'\n"; #输出BbCcbggggA } else { print "没有匹配到"; }
模式匹配中常用的一些修饰符:这些修饰符可以连用,连用时顺序可随意。
修饰符 | 描述 |
---|---|
i | 忽略模式中的大小写 |
m | 多行模式 |
o | 仅赋值一次 |
s | 单行模式,"."匹配"\n"(默认不匹配) |
x | 忽略模式中的空白 |
g | 全局匹配 |
cg | 全局匹配失败后,允许再次查找匹配串 |
#!usr/bin/perl -W use strict; use Spreadsheet::ParseExcel; use utf8; #引入utf8模块 脚本内的字符串使用utf8作为编码格式 binmode(STDOUT,":encoding(gbk)"); #标准输出使用gbk作为编码格式,也可以把gbk改为gb2312 binmode(STDIN,":encoding(gbk)"); #如果涉及到输入流,例如读文件,不加这条读中文文件会出现乱码 binmode(STDERR,":encoding(gbk)"); #如果异常错误中的字符串有中文,请加上STDERR,否则也会出现乱码 #全局匹配:会匹配多个ggg #perl中使用修饰符/g开启。当开启了全局匹配功能,这3个特殊变量保存的值需要使用循环语句去遍历,否则将只保存第一次匹配的内容。 my $str1="Abcggg777gggBbbCCC"; while($str1=~/ggg/g) { print "\n"; print "匹配到的内容:$&\n"; print "匹配前面部分的内容:$`\n"; print "匹配后面部分的内容:$'\n"; }
输出结果为
匹配到的内容:ggg
匹配前面部分的内容:Abc
匹配后面部分的内容:777gggBbbCCC
匹配到的内容:ggg
匹配前面部分的内容:Abcggg777
匹配后面部分的内容:BbbCCC
#!usr/bin/perl -W use strict; use Spreadsheet::ParseExcel; use utf8; #引入utf8模块 脚本内的字符串使用utf8作为编码格式 binmode(STDOUT,":encoding(gbk)"); #标准输出使用gbk作为编码格式,也可以把gbk改为gb2312 binmode(STDIN,":encoding(gbk)"); #如果涉及到输入流,例如读文件,不加这条读中文文件会出现乱码 binmode(STDERR,":encoding(gbk)"); #如果异常错误中的字符串有中文,请加上STDERR,否则也会出现乱码 my $str1="AbcgggGBbCcbggggA"; #忽略大小写 if($str1=~/gggg/i) { #如果想要输出匹配到的内容,可以使用特殊变量$&来引用匹配到的内容,还可以使用$`引用匹配前面部分的内容,$'引用匹配后面部分的内容 print "匹配到的内容:$&\n"; #输出gggG print "匹配前面部分的内容:$`\n"; #输出Abc print "匹配后面部分的内容:$'\n"; #输出BbCcbggggA } else { print "没有匹配到"; }
输出结果为
匹配到的内容:gggG
匹配前面部分的内容:Abc
匹配后面部分的内容:BbCcbggggA
#!usr/bin/perl -W use strict; use Spreadsheet::ParseExcel; use utf8; #引入utf8模块 脚本内的字符串使用utf8作为编码格式 binmode(STDOUT,":encoding(gbk)"); #标准输出使用gbk作为编码格式,也可以把gbk改为gb2312 binmode(STDIN,":encoding(gbk)"); #如果涉及到输入流,例如读文件,不加这条读中文文件会出现乱码 binmode(STDERR,":encoding(gbk)"); #如果异常错误中的字符串有中文,请加上STDERR,否则也会出现乱码 my $str1="AbcgggGBbCcbggggA"; #全局匹配加忽略大小写(顺序不做要求) # if($str1=~m/gggg/ig) while($str1=~/gggg/ig) { #如果想要输出匹配到的内容,可以使用特殊变量$&来引用匹配到的内容,还可以使用$`引用匹配前面部分的内容,$'引用匹配后面部分的内容 print "匹配到的内容:$&\n"; print "匹配前面部分的内容:$`\n"; print "匹配后面部分的内容:$'\n"; }
输出结果
匹配到的内容:gggG
匹配前面部分的内容:Abc
匹配后面部分的内容:BbCcbggggA
匹配到的内容:gggg
匹配前面部分的内容:AbcgggGBbCcb
匹配后面部分的内容:A
在开启了g全局匹配后,perl每次在成功匹配的时候都会记下匹配的字符位移,以便在下次匹配该内容时候,可以从指定位移处继续向后匹配。
每次匹配成功后的位移值(pos的位移从0开始算,0位移代表的是第一个字符左边的位置,第一个字符为1),都可以通过pos()函数获取。
#!usr/bin/perl -W use strict; use Spreadsheet::ParseExcel; use utf8; #引入utf8模块 脚本内的字符串使用utf8作为编码格式 binmode(STDOUT,":encoding(gbk)"); #标准输出使用gbk作为编码格式,也可以把gbk改为gb2312 binmode(STDIN,":encoding(gbk)"); #如果涉及到输入流,例如读文件,不加这条读中文文件会出现乱码 binmode(STDERR,":encoding(gbk)"); #如果异常错误中的字符串有中文,请加上STDERR,否则也会出现乱码 #全局匹配:会匹配多个ggg #perl中使用修饰符/g开启。当开启了全局匹配功能,这3个特殊变量保存的值需要使用循环语句去遍历,否则将只保存第一次匹配的内容。 my $str1="Abcggg777gggBbbCCC"; while($str1=~/ggg/g) { print "\n"; print "匹配到的内容:$&, 记录位置:", pos $str1 ,"\n"; print "匹配前面部分的内容:$`\n"; print "匹配后面部分的内容:$'\n"; }
输出结果为
全局匹配默认情况下失败的时候指针将会重置,回到0的位置,如果不想重置位移指针,可以在修饰符cg,就是将g和c结合使用。
本次匹配失败后,位移指针会向后移一位,下次匹配将从后移的这个位置处开始匹配。当位移移到了结尾,将无法再移动,此时位移指针将一直指向最后一个位置
#!usr/bin/perl -W use strict; use Spreadsheet::ParseExcel; use utf8; #引入utf8模块 脚本内的字符串使用utf8作为编码格式 binmode(STDOUT,":encoding(gbk)"); #标准输出使用gbk作为编码格式,也可以把gbk改为gb2312 binmode(STDIN,":encoding(gbk)"); #如果涉及到输入流,例如读文件,不加这条读中文文件会出现乱码 binmode(STDERR,":encoding(gbk)"); #如果异常错误中的字符串有中文,请加上STDERR,否则也会出现乱码 #全局匹配:会匹配多个ggg #perl中使用修饰符/g开启。当开启了全局匹配功能,这3个特殊变量保存的值需要使用循环语句去遍历,否则将只保存第一次匹配的内容。 my $str1="123456Tzx654321"; #修饰符cg将会保存当前位移,下面是使用g和cg的对比 $str1=~/\d\d/g; #匹配两个整数 print "matched:$&\t",pos $str1,"\n"; #匹配12 右移两位 $str1=~/xyt/g; print "matched:$&\t",pos $str1,"\n"; #未匹配 位移指针将重置到起始位置0处,也就是说,下次匹配将从头开始匹配,返回undef,无数据 print "\n"; $str1=~/\d\d\d/g; #匹配两个整数 print "matched:$&\t",pos $str1,"\n"; #匹配123 右移3位 $str1=~/xyt/cg; print "matched:$&\t",pos $str1,"\n"; #未匹配 保留上一次匹配的内容,下次匹配将从当前位置后移一位处开始匹配 输出 matched:123 3 $str1=~/\d/g; print "matched:$&\t",pos $str1,"\n"; #将会从123的后以为开始匹配,所以匹配到的是4,而不是从头开始匹配的结果1 输出 matched:4 4
输出结果为
matched:12 2
matched:12
matched:123 3
matched:123 3
my $str2="tzxghk9t78"; $str2=~/\d/cg; print "matched:$&\t",pos $str2,"\n"; #匹配到9 输出 matched:9 7 $str2=~/\d\d/cg; print "matched:$&\t",pos $str2,"\n"; #未匹配到 输出上次结果 matched:78 10 位移移到了最后,无法再移动,下次匹配开始的位移指针将永远在结尾 $str2=~/\d/cg; print "matched:$&\t",pos $str2,"\n"; #未匹配到 输出上次结果 matched:78 10 $str2=~/\d\d/cg; print "matched:$&\t",pos $str2,"\n"; #未匹配到 输出上次结果 输出上次结果 matched:78 10 $str2=~/\d\d/cg; print "matched:$&\t",pos $str2,"\n"; #未匹配到 输出上次结果 matched:78 10 $str2=~/\d/cg; print "matched:$&\t",pos $str2,"\n"; #未匹配到 输出上次结果 matched:78 10
输出结果为
matched:9 7
matched:78 10
matched:78 10
matched:78 10
matched:78 10
matched:78 10
\G的使用
指定\G
,使得本次匹配强制从位移处进行匹配,不允许跳过任何匹配失败的字符。
- 如果本次
\G
全局匹配成功,位移指针自然会后移 - 如果本次
\G
全局匹配失败,且没有加上c修饰符,那么位移指针将重置 - 如果本次
\G
全局匹配失败,且加上了c修饰符,那么位移指针将卡在那不动
#\G的使用 my $txt="1234ab56"; $txt =~ /\d\d/g; print "matched $&: ",pos $txt,"\n"; $txt =~ /\d\d/g; print "matched $&: ",pos $txt,"\n"; $txt =~ /\G\d/g; # 强制从位移4开始匹配,无法匹配字母a,但又不允许跳过 # 所以本次\G全局匹配失败,由于没有修饰符c,指针重置 print "matched $&: ",pos $txt,"\n"; $txt =~ /\G\d/g; # 指针回到0,强制从0处开始匹配,数值1能匹配成功 print "matched $&: ",pos $txt,"\n";
输出结果为:
matched 12: 2
matched 34: 4
matched 34:
matched 1: 1
再来举个例子比较使用\G并且在使用c修饰符和不使用c修饰符的输出结果
#不使用c修饰符
my $txt1="1234ab56"; while($txt1=~ m/\G\d\d/gc){ # 由于使用了c修饰符,当第三轮匹配字母失败的时候将一直卡在那个数字4的那个位置(4) print "matched: $&, ",pos $txt1,"\n"; } #将从4这个位置开始匹配两个数字,匹配失败,位置仍然在4这个位置 $txt1 =~ m/\G\d\d/gc; print "matched: $&, ",pos $txt1,"\n";
输出结果为
matched: 12, 2
matched: 34, 4
matched: , 4
#如果使用了c修饰符 my $txt2="1234ab56"; while($txt2 =~ m/\G\d\d/g){ # 不使用c修饰符,匹配失败将会回到0的位置 print "matched: $&, ",pos $txt2,"\n"; } #从0位置开始匹配 $txt2 =~ m/\G\d\d/gc; print "matched: $&, ",pos $txt2,"\n";
输出结果为
matched: 12, 2
matched: 34, 4
matched: 12, 2
多行匹配模式
一次性匹配多行。比如匹配跨行单词、匹配跨行词组,使用m修饰符可以开启多行匹配模式
.*表示匹配一次或者多次任意字符
my $txt="a7985\nxd"; $txt =~ /a.*\n.*/m; #a匹配a .*匹配7985 \n匹配换行 print "$&";
输出结果为
a7985
xd
元字符.(匹配换行符以外的任何字符)
默认情况下无法匹配换行符。可以使用[\d\D]
代替点,也可以开启s修饰符使得.
能匹配换行符。下面的代码和上述的输出结果一致。
my $txt="a7985\nxd"; $txt =~ /a[\d\D]*.*/m; #将会自动匹配换行符 #$txt =~ /a.*.*/ms; print "$&";
perl正则支持表达式的分隔,甚至支持注释,只需加上x修饰符即可,这时候正则表达式中出现的所有空白符号都不会当作正则的匹配对象,而是直接被忽略,这样可以使正则表达式可读性较好。如果想要匹配空白符号,可以使用\s
表示,或者将空格使用\Q...\E
包围。
my $ans="cat sheep tiger"; $ans =~ /(\w) *(\w) *(\w)/; # 正常情况下的匹配表达式,输出c a t print "$&\n"; #输出cat
#使用\s $ans = ~ / (\w)\s* # 可以加上本行注释:匹配第一个单词 \w表示匹配字母或者数字 \s表示匹配空格 \s*表示匹配0个或者多个空格 (\w)\s* # 可以加上本行注释:匹配第二个单词 (\w) # 可以加上本行注释:匹配第三个单词 /x;
print "$&\n"; #输出cat
#使用\q\e
$ans =~ / (\w)\q \e # \q \e强制将中间的空格当作字面符号被匹配 (\w)\q \e (\w) /x; print "$&\n"; #输出cat
p修饰符
前面说过,通过3个特殊变量$`
、$&
和$'
可以保存匹配内容之前的内容,匹配内容以及匹配内容之后的内容。但是,只要使用了这3个变量中的任何一个,后面的所有分组效率都会降低。perl提供了一个p修饰符,能实现完全相同的功能:
-
${^PREMATCH} <=> $`
-
${^MATCH} <=> $&
-
${^POSTMATCH} <=> $'
$ans="cat sheep tiger"; $ans =~ /sheep/p; print "${^PREMATCH}\n"; # 输出"cat " print "${^MATCH}\n"; # 输出"sheep" print "${^POSTMATCH}\n"; # 输出" tiger"
o修饰符
在较老的perl版本中,如果使用同一个正则表达式做多次匹配,正则引擎将只多次编译正则表达式。很多时候正则表达式并不会改变,比如循环匹配文件中的行,这样的多次编译导致性能下降很明显,于是可以使用o修饰符让正则引擎对同一个正则表达式不重复编译。
在perl5.6中,默认情况下对同一正则表达式只编译一次,但同样可以指定o修饰符,使得即使正则表达式变化了也不要重新编译。
一般情况下,可以无视这个修饰符。
范围模式匹配修饰符(?imsx-imsx:pattern)
前文介绍的修饰符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"放到了括号外,意味着这部分要区分大小写。所以匹配失败
my $s="Hello world gaoxiaofang"; #hello忽略大小写,world不忽略大小写 $s=~/(?i:hello) world/; print "$&\n"; #输出hello world
my $s="Hello\nworld gaoxiaofang";
my $s="Hello world gaoxiaofang";
#表示可以跨行匹配helloworld,也可以匹配单行的hello world,且hello部分忽略大小写。
$s=~/(?ims:hello.)world/; print "$&\n";#如果s是 Hello\nworld gaoxiaofang
my $s1="Hello world gaoxiaofang"; #s是匹配空格,匹配单行的hello world,且hello部分忽略大小写。 $s1=~/(?ims:hello.)world/; print "$&\n"; my $s2="Hello\nworld gaoxiaofang"; #跨行匹配helloworld,且hello部分忽略大小写。 $s2=~/(?ims:hello.)world/; print "$&\n";
单行匹配输出结果为
Hello world
多行输出匹配结果为
Hello
world
my $s1="Hello world gaoxiaofang"; $s1=~/(?i:hello (?-i:world) gaoxiaoFANG)/;#表示在第二个括号之前,可用忽略大小写进行匹配,但因为第二个括号里指明了去除i的影响,所以对world的匹配会区分大小写,但是对gaoxiaofang部分的匹配又不区分大小写。所以匹配成功 print "$&\n";#输出Hello world gaoxiaofang
更多正则表达式规则
表达式 | 描述 |
---|---|
. | 匹配除换行符以外的所有字符 |
x? | 匹配 0 次或一次 x 字符串 |
x* | 匹配 0 次或多次 x 字符串,但匹配可能的最少次数 |
x+ | 匹配 1 次或多次 x 字符串,但匹配可能的最少次数 |
.* | 匹配 0 次或多次的任何字符 |
.+ | 匹配 1 次或多次的任何字符 |
{m} | 匹配刚好是 m 个 的指定字符串 |
{m,n} | 匹配在 m个 以上 n个 以下 的指定字符串 |
{m,} | 匹配 m个 以上 的指定字符串 |
[] | 匹配符合 [] 内的字符 |
[^] | 匹配不符合 [] 内的字符 |
[0-9] | 匹配所有数字字符 |
[a-z] | 匹配所有小写字母字符 |
[^0-9] | 匹配所有非数字字符 |
[^a-z] | 匹配所有非小写字母字符 |
^ | 匹配字符开头的字符 |
$ | 匹配字符结尾的字符 |
\d | 匹配一个数字的字符,和 [0-9] 语法一样 |
\d+ | 匹配多个数字字符串,和 [0-9]+ 语法一样 |
\D | 非数字,其他同 \d |
\D+ | 非数字,其他同 \d+ |
\w | 英文字母或数字的字符串,和 [a-zA-Z0-9_] 语法一样 |
\w+ | 和 [a-zA-Z0-9_]+ 语法一样 |
\W | 非英文字母或数字的字符串,和 [^a-zA-Z0-9_] 语法一样 |
\W+ | 和 [^a-zA-Z0-9_]+ 语法一样 |
\s | 空格,和 [\n\t\r\f] 语法一样 |
\s+ | 和 [\n\t\r\f]+ 一样 |
\S | 非空格,和 [^\n\t\r\f] 语法一样 |
\S+ | 和 [^\n\t\r\f]+ 语法一样 |
\b | 匹配以英文字母,数字为边界的字符串 |
\B | 匹配不以英文字母,数值为边界的字符串 |
a|b|c | 匹配符合a字符 或是b字符 或是c字符 的字符串 |
abc | 匹配含有 abc 的字符串 (pattern) () 这个符号会记住所找寻到的字符串,是一个很实用的语法.第一个 () 内所找到的字符串变成 $1 这个变量或是 \1 变量,第二个 () 内所找到的字符串变成 $2 这个变量或是 \2 变量,以此类推下去. |
/pattern/i | i 这个参数表示忽略英文大小写,也就是在匹配字符串的时候,不考虑英文的大小写问题. \ 如果要在 pattern 模式中找寻一个特殊字符,如 "*",则要在这个字符前加上 \ 符号,这样才会让特殊字符失效 |
例如
my @errors = (); my $name=" PCUPFORCE"; #匹配以有空格开头的,字符结尾的字符 if($name =~ /^\s|\.$/) { print "success\n"; } else { print "failed"; }
输出结果
success
perl支持的反斜线序列
1.锚定类的反斜线序列
所谓锚定,是指它匹配的是位置,而非字符,比如锚定行首的意思是匹配第一个字母前的空字符。也就是很多人说的"零宽断言(zero-width assertions)"。
\b
:匹配单词边界处的空字符\B
:匹配非单词边界处的空字符\<
:匹配单词开头处的空字符\>
:匹配单词结尾处的空字\A
:匹配绝对行首,换句话说,就是输入内容的开头\z
:匹配绝对行尾,换句话说,就是输入内容的绝对尾部\Z
:匹配绝对行尾或绝对行尾换行符前的位置,换句话说,就是输入内容的尾部\G
:强制从位移指针处进行匹配,详细内容见g和c修饰符以及\G
b匹配单词边界,就是位于单词(\w)和非单词字符(\W)之间的零宽度的地方。单词前后必须跟非单词字符,这里的单词可以是中文字符,英文字符,数字。
my $s="哈2哈"; #b匹配单词边界,就是位于单词(\w)和非单词字符(\W)之间的零宽度的地方。单词前后必须跟非单词字符,这里的单词可以是中文字符,英文字符,数字。 if($s=~/\b/) { print "匹配成功\n"; } else { print "匹配失败\n"; } #B匹配非单词边界 my $s1="222"; if($s1=~/\B/) { print "匹配成功\n"; } else { print "匹配失败\n";
输出结果
匹配成功
匹配成功
\A \z \Z和^ (匹配字符开头的字符) $(匹配字符结尾的字符)的区别主要体现在多行模式下,见下面例子:
\A :匹配绝对行首
\Z:匹配绝尾部或者绝对行尾换行符前的位置
\z:匹配绝对行尾
^:匹配任意行首
$:匹配任意行尾
绝对行首可以理解为在有多个换行符的情况下默认为只有一个行首
任意行首理解为在有多个换行符的情况下有多个行首
绝对行尾只有最后一个换行
绝对行首只有开头一个换行
例:匹配任意行首和任意行尾
my $s="abcHello\nWorld\nABC7858"; #匹配任意行尾,失败 if($s=~/^ABC/) { print "$&\n"; } else { print "匹配失败!\n"; } #匹配任意行首,成功 if($s=~/^ABC/m) { print "$&\n"; } else { print "匹配失败!\n"; #输出ABC } #匹配成功 if($s=~/^abc/) { print "$&\n"; } else { print "匹配失败!\n"; #输出abc } #匹配成功 if($s=~/^abc/m) { print "$&\n"; } else { print "匹配失败!\n"; #输出abc }
例:匹配绝对行首
my $s="abcHello\nWorld\nABC7858AAA\n"; #匹配绝对行首 if($s=~/\Aabc/) { print "$&\n"; #输出abc } else { print "匹配失败!\n"; } #匹配绝对行首,失败 if($s=~/\ABC/) { print "$&\n"; } else { print "匹配失败!\n"; }
例:匹配绝对行尾
my $s="abcHello\nWorld\nABC7858AAA\n"; #匹配绝对行尾,成功 if($s=~/AAA\n\z/) { print "$&\n"; #输出AAA } else { print "匹配失败!\n"; } #匹配绝对行尾,失败 if($s=~/AAA\z/) { print "$&\n"; } else { print "匹配失败!\n"; }
例:匹配绝对行首或者绝对行尾换行符前的位置
my $s="abcHello\nWorld\nABC7858AAA\nCCC\nccc"; #匹配绝对尾部或者绝对行尾换行符前的位置,失败 if($s=~/AAA\n\Z/) { print "$&\n"; #输出AAA } else { print "匹配失败!\n"; } #匹配绝对尾部或者绝对行尾换行符前的位置,成功 if($s=~/CCC\Z/) { print "$&\n";#输出CCC } else { print "匹配失败!\n"; } #匹配绝对尾部或者绝对行尾换行符前的位置,成功 if($s=~/CCC\n\Z/) { print "$&\n";#输出CCC } else { print "匹配失败!\n"; }
my $s1="abcHello\nWorld\nABC7858AAA\nCCC\nccc"; #匹配绝对尾部或者绝对行尾换行符前的位置,成功 if($s1=~/ccc\Z/) { print "$&\n";#输出ccc } else { print "匹配失败!\n"; }
贪婪匹配、非贪婪匹配、占有优先匹配
在基础正则中,那些能匹配多次的量词都会匹配最长内容。这种尽量多匹配的行为称为"贪婪匹配"(greedy match)。
例如字符串"aa1122ccbb",用正则表达式a.*c
去匹配这个字符串,其中的.*
将直接从第二个字母a开始匹配到最结尾的b,因为从第二个字母a开始到最后一个字母b都符合.*
的匹配模式。
再然后,去匹配字母c,但因为已经把所有字母匹配完了,只能回退一个字母一个字母地释放,每释放一个就匹配一次字母c,发现回退释放到倒数第三个字母就能满足匹配要求,于是这里的.*
最终匹配的内容是"a1122c"。
贪婪匹配行为,非贪婪匹配、占有优先匹配意义:
- 贪婪匹配:对于那些量词,将一次性从左到右匹配到最大长度,然后再往回回溯释放
- 非贪婪匹配:对于那些量词,将从左向右逐字符匹配最短长度,然后直接结束这次的量词匹配行为
- 占有优先匹配:按照贪婪模式匹配,匹配后内容就锁住,不进行回溯(后文固化分组有具体示例)
my $s="tzx1a23tzx453b612c4"; #贪婪匹配,尽可能的输出最长,匹配成功 if($s=~/t\w*3/) #\w*表示匹配o次或者多次字母或者数字 { print "$&\n"; #输出tzx1a23tzx453 } else { print "匹配失败!\n"; } #懒惰匹配,尽可能的输出最短,匹配成功 if($s=~/t\w*?3/) #\w*表示匹配o次或者多次字母或者数字 X?表示匹配0次或一次x字符串 { print "$&\n"; #输出tzx1a23 } else { print "匹配失败!\n"; }
占有优先匹配,按照贪婪模式匹配,匹配后内容就锁住,不进行回溯
my $str="abc123abc1234"; if( $str =~ /a\w*+/){ # 成功 首先a\w*+将会找到abc123abc1234,a x+表示匹配一次的到多次x
print "possessive1: $&\n"; #输出bc123abc1234
}
if( $str =~ /a\w*+3/){ # 失败,因为不回朔找不到3 print "possesive2: $&\n"; }
s///修饰符
s/原来字符串/目的字符串/修饰符
my $str1=" CATALOG";
#将空格用_来代替 print $str1 =~ s/\s/_/g; print "$str1\n";
输出
1
_CATALOG