相关阅读
Perl:什么是其特有的autovivafacation性质?
前言
正则表达式(Regular Expression),换一种叫法也是规则的表达式,最早追溯到了20世纪50年代,一位美国数学家,斯蒂芬·科尔·克莱尼(Stephen Cole Kleene),发明了规则的语言(Regular Language)的定义,而规则的表达式则是用来描述规则的语言的表达式。肯尼斯·蓝·汤普森(Kenneth Lane Thompson),没错,就是那位发明了UNIX的专家,他借用了这个概念,将其应用到了UNIX上的ed和grep。ed是一个文本编辑器,虽然现在很少有人会用了,但它的正则表达式基因进入了后起之秀vi和vim之中。grep是UNIX/Linux的常用命令,它的名字来源于Globally search a Regular Expression and Print的缩写,功能是查找符合某种规则的表达式。但这时的正则表达式的语法比较难看,这促使拉里·沃尔(Larry Wall)发明了一门语言——Perl,他和Perl社区一起增强了Perl语言的正则表达式功能,直到Perl 5发布,其中内建的正则表达式功能已经登峰造极,成为了Perl最引人注目的特性。
Perl内建的正则表达式引擎可以根据你给出的模式(pattern)串,与主串进行匹配,并且还可以捕获(capture)和替换(replace)等功能。具体来说,正则表达式处理的对象一般为字符串,它可以完成以下功能:
确认模式串是否匹配了主串。
把模式串匹配的内容捕获出来。
把模式串匹配的内容替换成指定的内容。
匹配的基本过程
Perl提供了一个专门的操作符=~来进行匹配、捕获和替换,操作符的左侧是待匹配的字符串即主串,右侧则是模式串,模式串一般使用一对斜杠/.../包围,且模式串无需使用""包围。如下所示:
$string=~/regular expression/
可以通过一个简单的例子来看一看匹配的过程。
my $str1 = "aAcABC" ;
if ( $str1 =~ /AB/ ) {
print "match\n" ;
}
else {
print "unmatch\n" ;
}
exit 0;
以上代码的输出是match。我们来看看第三行作为if条件表达式的模式匹配是如何进行的。首先将主串和模式串左边对齐,即
$str1 | a | A | c | A | B | C |
/AB/ | A | B |
我们发现此时模式串与主串不匹配,接着将模式串向右平移一个字符,即
$str1 | a | A | c | A | B | C |
/AB/ | A | B |
模式串中的A与主串中的A匹配,但模式串中的B与主串中的c不匹配,将模式串向右平移一个字符,即
$str1 | a | A | c | A | B | C |
/AB/ | A | B |
模式串中的A与主串中的c不匹配,将模式串向右平移一个字符,即
$str1 | a | A | c | A | B | C |
/AB/ | A | B |
此时匹配成功,匹配表达式返回匹配成功的数量1,即真;如果没有匹配成功,则返回0。
$string=~/regular expression/实际上是简写形式,完整的是$string=~m/regular expression/,其中m表示match(匹配)。
如果使用完整形式,模式串的界定符//,可以换成成对的括号:
$string=~m(regular expression)
$string=~m[regular expression]
$string=~m{regular expression}
$string=~m<regular expression>
甚至可以是其他字符,但需要保证首尾使用相同的字符,如:
$string=~m!regular expression!
$string=~m^regular expression^
$string=~m?regular expression?
匹配
本节分几个小节介绍了正则表达式的模式匹配功能,即判断模式串是否匹配主串。
本章只包含ASCII字符集中的可见字符和空白字符,包括普通空格(space)、水平制表符(tab)和换行符(\n),不包括其他不可见字符。
3.1 普通字符
大多数字符没有特殊含义,在模式串中表示自身本意,如数字、英文字母和下划线等。
"A"=~/A/ #match
"100"=~/0100/ #match
"B"=~/b/ #unmatch
3.2元字符
Perl中有12个特殊字符,在模式串中有特殊含义,常被称为元字符(meta character),列表如下:
* | + | ? | . |
( | ) | [ | { |
^ | $ | | | \ |
下面依次介绍这12个元字符。
星号*
*表示其左侧的字符(或字符组)可以有任意数量,零或任意多个,由()或者[]包围的字符集合就是字符组。下表是一些*的例子。
模式串 | 匹配的字符串 | 不匹配的字符串 |
/B*/ | 任意字符串,包括空串(因为模式串可以是空串) | 无 |
/AB*/ | A、AB、ABB、ABBB...... | C、D、BA...... |
加号+
表示其左侧的字符(或字符组)可以有一个或任意多个。下表是一些+的例子。
模式串 | 匹配的字符串 | 不匹配的字符串 |
/B+/ | B、BA、BB、BBA、BBB、BBBA...... | A、AB、AD...... |
/AB+/ | AB、ABB、ABBB、BAB、BABB...... | C、D、AA、BA...... |
在默认情况下,+*会优先匹配更多的字符串,即贪婪匹配。举个例子/B+/默认优先尝试在主串中匹配BBB然后才是BB,这在之后的捕获中很重要。
问号?
表示其左侧的字符(或字符组)可以有零个或一个。下表是一些?的例子。
模式串 | 匹配的字符串 | 不匹配的字符串 |
/B?/ | 任意字符串,包括空串(因为模式串可以是空串) | 无 |
/AB?/ | AB、A、BA、BAB...... | C、D、AA、BA...... |
大括号{}
其中可以有两个数字,由逗号分隔,左边的数字小,右边的数字大,表示其左侧的字符(或字符组)的数量区间,且区间包括两侧的数字(闭区间);或者只有单侧的数字和逗号,{,n}表示0到n的闭区间,{n,}表示大于等于n;或者其中只有一个数字(无逗号),表示确切数量。下表是一些{}的例子。
模式串 | 匹配的字符串 | 不匹配的字符串 |
/AB{3,4}C/ | ABBBC、ABBBBC...... | AC、ABC、ABBC、ABBBBBC...... |
/AB{,2}C/ | AC、ABC、ABBC、BABBC...... | ABBBC、BABBBC...... |
/AB{2,}C/ | ABBC、ABBBC、ABBBBC...... | ABC、AC、BABC...... |
/AB{3}C/ | ABBBC、BABBBC、AABBBC...... | ABBBBC、ABBC、BABBC...... |
我们可以看到,{}和*、+、?有对应关系,如下表所示。
元字符 | 等价关系 |
* | {0,} |
+ | {1,} |
? | {0,1} |
我们之前介绍的都是单字符的重复,也提到了字符组这个东西,圆括号()就有分组的功能,它还是捕获的元字符,本节我们介绍前者,捕获的内容留到后面再说。
圆括号()
表示其间的所有字符是一个整体(字符组)。如果想要在字符组中包括(或),需要在之前加反斜杠\转义。下表是一些()的例子。
模式串 | 匹配的字符串 | 不匹配的字符串 |
/(ABC)+/ | ABC、ABCABC、ABCABCABC | AABBCC、BAC...... |
/A(ABC)+/ | AABC、AABCABC...... | AAC、AAB...... |
方括号[]
主要有两种用法:
表示其间的一个和多个字符作为一个可选的字符组,匹配其中任何一个字符即可(注意,这里也是从左往右在字符组里面尝试)。
模式串 | 匹配的字符串 | 不匹配的字符串 |
/[Ww]ord/ | Word、word...... | Cord、ord...... |
如果想要在字符组中包含[或者]本身,需要在之前加反斜杠\转义。
模式串 | 匹配的字符串 | 不匹配的字符串 |
/A[b\[c]D/ | AbD、A[D、AcD...... | AD、AAD...... |
/A[b\]c]D/ | AbD、A]D、AcD...... | AD、AAD...... |
字符组还可以使用-指定范围,用来便捷的包括一个字符集,如[0-9]表示任意一个数字,[a-z]表示所有小写字母(其实这里是指定了ASCII码的范围)。如果想要在字符组中包含-,可以将其放在[]内的最左侧,即第一个字符,或者最右侧,即最后一个字符。
模式串 | 匹配的字符串 | 不匹配的字符串 |
/A[0-9]D/ | A0D、A1D、A2D...... | AXD、A99D...... |
/A[-bB]D/ | A-D、AbD、ABD...... | AD、AAD...... |
如果[]内的第一个字符是^,[^...]表示出了...以外的字符组成的字符组。
模式串 | 匹配的字符串 | 不匹配的字符串 |
/A[^cd]D/ | AbD、A1D、A2D...... | AcD、AdD...... |
本小节开始时,我们知道了12个元字符,其中并不包括]和}这两个右括号。所以,如果想单独匹配(注意,这里指}不在一对大括号内,]不在一对中括号内,如果在则仍需要反斜杠\转义)]或},直接输入他们即可。
模式串 | 匹配的字符串 | 不匹配的字符串 |
/A]B/ | A]B...... | AB、A[D...... |
/A}B/ | A}B...... | AB、A{D...... |
竖线|
表示其两侧的字符(字符组),二选一匹配其中一个即可(两侧从左向右检索))下表是一些|的例子。
模式串 | 匹配的字符串 | 不匹配的字符串 |
/a|b/ | a、b、aa、bb...... | c、d...... |
/worda|wordb/ | worda、wordb、aworda、bwordb...... | wordc、wordd...... |
如果还希望在模式中加入更丰富的内容,比如,部分内容是二选一,其他内容是固定的,则需要把可选部分使用圆括号包围,如下表所示。
模式串 | 匹配的字符串 | 不匹配的字符串 |
/Tom and (Jerry|me)/ | Tom and Jerry、Tom and me...... | Tom and others...... |
如果想要单字符二选一,可以使用[ab]或(a|b),(a|b)还有捕获功能。
反斜杠\
之前,我们已经见过\了,它的一类功能就是放在原字符前,则会撤销该元字符的特殊功能,使元字符变成一个普通字符,仅匹配自身。下表是一些\的例子。
\放在某些普通字符前,能组成特殊字符(字符组)或有其他含义。这部分内容较多,将放在下一节单独列出。
模式串 | 匹配的字符串 | 不匹配的字符串 |
/ab\*cd/ | ab*cd...... | abcd、abbcd...... |
/\(abd\)/ | (abc)...... | abc...... |
/ab\\cd/ | ab\cd...... | abcd...... |
句点.
.匹配任意一个字符,一般情况下,不匹配换行符\n,除非模式有s修饰符(在之后会介绍修饰符)。下表是一些.的例子。
模式串 | 匹配的字符串 | 不匹配的字符串 |
/abc.e/ | abcde、abcfe、"abc e"...... | abce、"ac\ne"...... |
当.在[]中,只匹配.自身,不在匹配任意一个字符。即无需转义字符\,也可匹配.自身。
尖角^
当^出现在模式的开头时,表示匹配字符串的行开头,此时的模式匹配过程使得,在每行内不会尝试将模式串向右移。如果待匹配的字符串只有一行,即中间没有换行符\n,那么^等同于只匹配字符串的开头。下表是一些^的例子。
模式串 | 匹配的字符串 | 不匹配的字符串 |
/^abc/ | abc、abcd...... | aabc、1abc...... |
如果待匹配的字符串是多行文本,如:
$str = "this is
an example
of multi-lines";
那么/^this/、/^an/、/^of/都能匹配$str。
另外,当^出现在[]开头时,表示排除^后面的字符而形成的字符组,如果要想字符组中有^,则不要讲其放在[]的开头。
美元符$
当美元符$出现在模式的结尾时,表示匹配字符串的行结尾。如果待匹配的字符串只有一行,即中间没有换行符\n,那么^等同于只匹配字符串的结尾。下表是一些$的例子。
模式串 | 匹配的字符串 | 不匹配的字符串 |
/abc$/ | abc、2abc...... | abcd、abc2...... |
/^abc$/ | 只有abc | 除了abc外的所有字符串 |
如果待匹配的字符串是多行文本,如:
$str = "this is
an example
of multi-lines";
那么/is$/、/example$/、/lines$/都能匹配$str。
$还有一个功能,就是表示一个变量,将变量的值嵌入模式串中。这个功能将在后面介绍。
3.3反斜杠\
鉴于反斜杠\会影响后面字符的含义,且组合较多,我们单独用一节来讨论。
它的功能可以分为三类:
放在元字符前,撤销该元字符的特殊含义,使元字符仅匹配自身。
与后续某些字符组合,表示特定字符组,常用的如下表所示。
组合 | 含义 |
\d | 数字的集合,等价于[0-9] |
\D | 非数字的集合,等价于[^0-9] |
\n | 表示换行符 |
\s | 表示空白字符 |
\S | 表示非空白字符 |
\t | 表示水平制表符tab |
\w | 数字、字母和下划线的集合,等价[_0-9a-zA-Z]) |
\W | 表示除了\所表示的字符以外的字符组,等价于[^_0-9a-zA-Z] |
补充说明:在本章开头,已经声明了我们是在ASCII范围内讨论。所以我们简化了一些描述。比如\w还可以匹配非ASCII字符,意思是只有在ASCII字符集内,它才等价于[_0-9a-zA-Z]。其他特殊字符组可能也有类似情况,当应用范围超出ASCII字符集时,请查阅Perl官方文档获得更精确的说明。
与后续字符组成某类锚位,用来匹配模式的位置,常用的如下表所示。
组合 | 含义 |
\A | 字符串的开头 |
\b | “单词”的边界,“单词”由数字、字母和下划线组成。边界指字符串的开头、结尾、"单词”与“非单词”之间的位置(没有宽度,指字符间的位置) |
\z | 字符串的结尾 |
\Z | 字符串的行结尾,等价于模式串结尾处的$ |
\b模式的例子如下所示。
模式串 | 匹配的字符串 | 不匹配的字符串 |
/\beat\b/ | eat、to eat、eat to | heat、eaten |
如果待匹配的字符串是多行文本,如下所示。
$str = "this is
an example
of multi-lines";
下表是几个例子。
模式串 | 是否匹配$str | 模式串 | 是否匹配$str |
/\Athis/ | 是 | /is\z/ | 否 |
/\Aan/ | 否 | /lines\Z/ | 是 |
/lines\z/ | 是 | /is\Z/ | 是 |
3.4修饰符
在模式的尾部/之后,可以添加一些修饰符,调整该模式的匹配功能,如下表所示。
修饰符 | 含义 | 模式串 | 匹配的字符串 |
i | 匹配时不区分大小写 | /abc/i | abc、Abc、ABC |
s | 使句点号.匹配换行符 | /a.*b/s | "a\nb" |
x | 忽略模式中的空白字符 | /a b/x | ab |
x修饰符会忽略模式中包含的空白字符,使我们可以把很长的模式(可读性差)以(任意数量的)空白(包括换行符)分隔开。
/^[0-9]{4}-.{7,10}-[^-]+-\d{2,5}#8$/
等价于:
/^ [0-9]{4}
-
.{7,10}
-
[^-]+
-
\d{2,5}
#8
$/x
有了修饰符x,我们还可以在模式中添加注释#,进一步提高代码的可读性。
/^ [0-9]{4} # four digital
-
.{7,10} #any string contains 7-10 characters
-
[^-]+ #DO NOT write / here !!!
-
\d{2,5}
#8
$/x
添加注释时,需要注意两点:
注释中不能出现模式的终止符号,上例中是/。
如果添加了#注释,那么原先模式中的#,则需要换成\#或者[#]。
还有一个常用的修饰符g,将在后面进行介绍。
3.5内插变量
前面几小节中,模式串的内容都是常量,是不可改变的。如果有很多模式串需要匹配,我们可以在模式串中直接使用变量(注意,变量要加$前缀,这并不会和模式串结尾可能的元字符$混淆)。下面我们看一个例子。
#!/usr/local/bin/perl
my @lines = (
"China_capital Beijing",
"China Shanghai",
"Japan Toyko",
"USA Newyork",
"USA_capital DC",
);
my @countries = (
"China",
"USA",
);
for my $line ( @lines ) {
for my $country ( @countries ) {
if ( $line =~ /$country/ ) {
print $line, "\n";
}
}
}
exit 0;
运行上述代码,得到输出如下:
China_capital Beijing
China_Shanghai
USA Newyork
USA_capital DC
我们直接在模式中书写变量即可,如第18行。
如果我们需要只匹配有首都的行,需要稍作修改,不能想当然地使用
if( $line =~/$country_capital/)
因为Perl解释器无法知道变量名的结尾在哪里,为了精确定义变量名的范围,我们可以使用{},即
if( $line =~/${country}_capital/)
或者也可以引入():
if( $line =~/$country()_capital/)
在上式中,()(中间没有空格)插在变量名的结尾,阻断了Perl试图读取更长的变量名。
在任何可以插入变量的位置,都可以插入数组的元素和散列的值。
有了变量,我们可以匹配的自由度就会提高,但还不够。下一节将会了解正则表达式更强大的功能。
4.分组和捕获
在本节中,我们要学习本章开始时提出的一个功能——把字符串中匹配了模式的内容捕获出来,即分组(grouping)和捕获(capture)。
圆括号完成分组和捕获的功能。
4.1分组并捕获
请先看一个实例。
#!/usr/local/bin/perl
my $str = "module xyz something";
if ( $str =~ /^module\s+(\S+)/ ) {
print "module name is: ", $1, "\n";
}
exit 0;
运行上述代码,会输出:
modole name is:xyz
模式串 /^module\s+(\S+)/中的^表示匹配开头,module匹配成功后,匹配一个空格,然后匹配三个非空格字符,而且\S+是被()包括,这代表捕获()中的内容。
注意,这里不能写成/^module\s+(\S)+/否则只会捕获z而不是把xyz作为一个整体捕获。
捕获完成了之后,存到哪里呢?Perl内置了9个变量:$1、$2、$3、... 、$9,按照左括号出现的顺序,依次存放9组括号捕获的内容。下面再看一个例子。
#!/usr/local/bin/perl
my $str = "To be or not to be, it’s a question.";
if ($str =~ /^((\S+)\s+(\S+))\s+(\S+)\s+((\S+)\s+(\S+)\s+(\S+))\s+(.+)/) {
for my $n ( 1..9 ) {
print "\$$n is: ${$n}\n";
}
}
exit 0;
运行代码的输出如下:
$1 is: To be
$2 is: To
$3 is: be
$4 is: or
$5 is: not to be,
$6 is: not
$7 is: to
$8 is: be,
$9 is: it’s a question.
如果我们想捕获更多的字符,9个预设的变量就不够了,我们可以把捕获的内容存到一个数组中去。稍加修改,可以得到以下代码。
#!/usr/local/bin/perl
my $str = "To be or not to be, it’s a question.";
my @caps;
if ( @caps = $str =~ /^((\S+)\s+(\S+))\s+
(\S+)\s+
((\S+)\s+(\S+)\s+(\S+))\s+
([^.]+)
(((.)))
/x ) {
for my $n ( 0..$#caps ) {
print 1+$n, " is: $caps[$n]\n";
}
}
exit 0;
运行代码的输出如下:
1 is: To be
2 is: To
3 is: be
4 is: or
5 is: not to be,
6 is: not
7 is: to
8 is: be,
9 is: it’s a question
10 is: .
11 is: .
12 is: .
我们在第5行使用了一个数组@caps,if条件表达式的执行情况是这样的:首先进行正则表达式匹配,然后由于赋值表达式左侧是一个数组(或散列),此时模式匹配处于列表上下文环境中,模式匹配返回捕获的内容(而不是匹配到的数量)。
如果太多的圆括号让你眼花缭乱,我们可以采用命名变量?<>,将?<>放置在捕获圆括号内的最左侧,?<>的尖括号内是名称。
#!/usr/local/bin/perl
my $str = "To be or not to be, it’s a question.";
if ( $str =~ /^(?<first_two_words>(\S+)\s+(?<second_word>\S+))/ ) {
print "First two words is: $+{'first_two_words'}\n";
print "Second word is: $+{'second_word'}\n";
}
exit 0;
代码的输出结果如下所示:
First two words is: To be
Second word is: be
?<>尖括号内的名词是散列%+中的键名。
4.2匹配的特点
模式匹配有两个特点:
尽可能多地匹配(贪婪匹配)。
匹配达成后就结束。
我们可以看以下例子。
#!/usr/local/bin/perl
use strict;
my $str = "To be or not to be, it’s a question.";
if ( $str =~ /(.+)/ ) {
print "Matched is: ", $1, "\n";
}
exit 0;
运行代码会输出:
Matched is: To be or not to be, it’s a question.
将第5行的+换成*,输出结果是一样的,他们都有“贪婪”得特点,尽可能匹配更多的字符。在某些情况下,我们希望它们不要匹配太多字符,留一些给后面的模式串。那么,我们可以后置?来约束+和*,使它们尽量少匹配。
一个例子如下所示。
#!/usr/local/bin/perl
use strict;
my $str = "To be or not to be, it’s a question.";
if ( $str =~ /(.+?)/ ) {
print "Matched is: ", $1, "\n";
}
exit 0;
运行代码会输出:
Matched is: T
注意,.+?优先匹配一个字符,.*?优先匹配零个字符。
我们再来看看第二个特点。
#!/usr/local/bin/perl
use strict;
my $str = "To be or not to be, it’s a question.";
if ( $str =~ /be(.{4})/ ) {
print "Matched is: ", $1, "\n";
}
exit 0;
运行代码会输出:
Matched is: or
实际匹配的是“ or ”四个字符(前后各有一个空格)。一旦匹配到了,匹配就会结束,无论后面是否有匹配的可能,都不会尝试继续匹配后面的字符串。如果需要匹配所有的情况,则需要使用之前提到过的g修饰符,并且如果要捕获,则需使用外部数组来接受正则表达式匹配的返回值。如下所示。
#!/usr/local/bin/perl
use strict;
my @caps;
my $str = "To be or not to be, it’s a question.";
if ( @caps = $str =~ /be(.{4})/g ) {
for my $cap ( @caps ){
print "Matched is: ", $cap, "\n";
}
}
exit 0;
运行以上代码会输出:
Matched is: or
Matched is: , it
为什么不能使用内置变量$1和$2呢?因为代码中只有一组圆括号,即便匹配了两次,“ or ”和“, it”也是先后存储至$1,而$2是未被赋值的。
4.3分组不捕获
有时,我们仅使用()分组,而不捕获其中的内容。我们可以使用(?:),如以下所示。
#!/usr/local/bin/perl
use strict;
my $str = "module xyz (something)";
if ( $str =~ /^(?:module)\s+(\S+)/ ) {
print "module name is: ", $1, "\n";
}
exit 0;
以上代码输出:
module name is: xyz
以上代码的模式串中有两组圆括号,但是第一组采用了(?:)的形式,即仅分组,不捕获。所以$1内存放的是第一对没有?:的圆括号内捕获的内容,即(\S+)。
4.4分组捕获并反向引用
有时,我们希望在模式内部,即刻引用左侧已部分匹配并捕获成功的内容(即反向引用),作为后续匹配的变量。举一个例子,我们要检查一个单词开头的两个字符,如果两个字符一样,那么很有可能是一个错误,将其输出。
#!/usr/local/bin/perl
use strict;
my $str = "To bbe or not to be, it’s a question.";
if ( $str =~ /\b((.)\2\S*)\b/ ) {
print "Warning: $1\n";
}
exit 0;
运行代码的输出结果如下:
Warning: bbe
模式/\b((.)\2\S*)\b/中的\2是反向引用了第2组圆括号内,即(.)匹配的内容,注意,这里必须使用带有捕获功能的括号。(.)\2组成了两个一样的字符。后面紧跟任意数量的非空白字符。在模式外部,捕获这个疑似出错的单词的是变量$1。不要和内部反向引用变量\1混淆。诸如\1,\2的反向引用变量,一共有且只有9个:\1、\2、......、\9。
如果想反向引用的变量超过9个,则可以使用\g{N},N为数字。如下所示。
#!/usr/local/bin/perl
use strict;
my $str = "1234567800";
if ( $str =~ /(.)(.)(.)(.)(.)(.)(.)(.)((.)\g{10})/ ) {
print "Warning: $9\n";
}
exit 0;
代码的输出结果如下:
Warning: 00
反向引用\N或\g{N}只能出现在模式内,不能在模式外使用。
5.替换
本节我们将学习本章开始时提出的最后一个功能——把字符串中匹配的内容替换成指定内容。
替换是在模式匹配的基础上,使用s操作符,并在第2个/右侧(即第2组//中)添加替换后的内容,如下所示:
$str =~ s/regular expression/replacement/
替换是把第二个/左侧匹配的所有内容,都替换成右侧的字符串(可以包含变量)。注意,第二组//中的替换内容不是正则表达式,只是字符串。如果匹配和替换成功,则左侧的变量会立刻被改变。
$str = "abcde";
$str =~ s/bcd/BCD/; #now $str is :aBCDe
在替换部分可以加入变量。
$replace = "BCD";
$str = "abcde";
$str =~ s/bcd/$replace/; #now $str is :aBCDe
在替换部分也可以加入左侧模式中分组捕获的内容(因为替换时,模式匹配已经结束):
$str = "abcde";
$str =~ s/(bcd)/$1/; #now $str is: abcde
$str = "abcde";
$str =~ s/(.)/$2$1/; #now $str is: bacde
5.1修饰符
此前介绍的模式匹配的修饰符,都可在s///尾部使用,意义基本相同。比较常用的是使用/g将匹配的内容全部替换。
$str = "abcde abcde";
$str =~ s/bcd/BCD/; #now $str is :aBCDe abcde
$str = "abcde abcde";
$str =~ s/bcd/BCD/g; #now $str is :aBCDe aBCDe
5.2界定符
此前我们介绍过,模式匹配的界定符,除了最常用的//,还可以是其他成对的括号,或者其他字符。在替换中,事实上有两组界定符,他们既可以是相同的:
$str =~ s{regular expression}{replacement}
也可以是不同的:
$str =~ s{regular expression}<replacement>
5.3不改变原变量
如果不希望改变原变量,则需要先复制备份:
$str1 = "abcde abcde";
$str2 = $str1;
$str2 =~ s/bcd/BCD/; #now $str2 is :aBCDe abcde
常简写成:
(str2 = $str1)=~ s/bcd/BCD/
如果不使用括号的话,由于正则匹配的优先级高于赋值,这里又是标量上下文,则会把匹配的数量赋值给$str2。
以上内容来源于《Perl语言IC设计实践》