1. 用m//进行匹配
到目前为止,都是把正则表达式写在一对斜线内,比如/fred/,这是简写版本,完整写法是m//(模式匹配操作符),这里的m表示英文match(匹配),和之前看过的qw//类似,可以自行选择用于包围内容的一对字符作为边界
所以可以还可以改写成m(fred)、m<fred>、m{fred}、m[fred]
不成对定界符没有左右之分,模式2边用同样的字符界定即可
如果选择一对斜线作为定界符,则可省略开头的m
最常见的定界符是花括号
尖括号(<与>)不是正则表达式元字符,所以它们可能不会成对出现
2. 模式匹配修饰符
正则表达式末尾可以追加一些修饰用的字符,用以调整模式的匹配行为,这些修饰符有时也被称为标志(flag)
1. 用/i进行大小写无关的匹配
print "Would you like to play a game? ";
chomp($_ = <STDIN>);
if(/yes/i){ # 大小写无关的匹配
print "In that case, I recommend that you go bowling.\n";
}
2. 用/s匹配任意字符
默认情况下,点号(.)不能匹配换行符,这符合我们“从1行文本”中寻找匹配这个常见需求
/s修饰符会将模式中每个点号转换为字符集[\d\D]来匹配
$_ = "I saw Barney\ndown at the bowling alley\nwith Fred\nlast night.\n";
if(/Barney.*Fred/s){ # 没有/s修饰符的话,这个匹配会失败,因为Barney和Fred这2个名字不在同1行里
print "That string mentions Fred after Barney!\n";
}
.匹配的字符集可以修改
3. 用/x加入辅助空白字符
/x修饰符允许在模式里任意加入空白字符,从而使它更易阅读、理解
/-?[0-9]+\.?[0-9]*/
都挤在一起,很难看清是什么意思
/-? [0-9]+ \.? [0-9]*/x
加入辅助空白后容易知道什么意思
因为加上/x后模式里可以随意插入空白,所以原来表示空格和制表符本身的空白字符就失去了意义
可以在空格前加上反斜线来转义,使用\t,或者使用\s(\s*,\s+),或者\x{20},\040
可以在模式中写上注释,因为perl还会把模式中出现的注释当作空白字符直接忽略
/
-? # 一个可有可无的减号
[0-9]+ # 小数点前必须出现1个或多个数字
\.? # 一个可有可无的小数点
[0-9]* # 小数点后的数字,有没有都可以
/x
因为#是注释的标记,表示井号本身时,需要写成\#
,或者写成字符集[#]
/
[0-9]+ # 小数点前必须出现1个或多个数字
[#] # 井号字符本身
/x
需要注意的是,注释部分不要使用定界符,否则会被视为模式终点
/
-? # 有减号/没有减号 <--- 这里的斜线会被当作模式结尾
[0-9]+
\.?
[0-9]*
/x
4. 联合使用修饰符
将多项修饰符接在一起写到末尾,前后顺序无关
if(/barney.*fred/is){ # 同时使用/i和/s
print "That string mentions Fred after Barney!\n";
}
if(m{ # 使用花括号作为定界符
barney
.*
fred
}six){
print "That string mentions Fred after Barney!\n";
}
5. 选择字符的解释方式
perl5.14开始增加了一些用于告诉perl如何解释字符意义的修饰符,着重于
- 对大小写的处理
- 对字符集合简写的阐释
/a
对字符集合采取ASCII方式解释
/u
以unicode方式解释
/l
根据本地化语言的设定
如果不提供修饰符,perl会根据perlre文档中描述的方式采取合适的解释方式
use v5.14;
/\w+/a # 仅仅是A-Z、a-z、0-9、_这些字符
/\w+/u # 任何unicode中定义为单词的字符
/\w+/l # 类同于ASCII的版本,但单词字符的定义取决于本地化设定
涉及大小写处理的问题,需要知道如何通过大写字母得到对应的小写字母,在perl中属于"unicode bug",字符对应关系实际上在系统内部就写好,具体细节可以看perlunicode文档
小写到大写的映射不是一一对应的
单个/a
表示按照ASCII方式解释简写意义,使用2个/a
表示仅仅采取ASCII方式的大小写映射处理
/k/aai # 只匹配ASCII字符K或k,但不匹配开尔文字符
/k/aia # /a不需要紧挨着写
/ss/aai
/ff/aai
如果不知道本地化设定是什么字符编码,就无法进行大小写转换的处理
通过chr()
函数构造字符,以免源代码编码不一致
$_ = <STDIN>;
my $OE = chr(0xBC);
if(/$OE/i){
print "Found $OE";
}
如果程序源代码用UTF-8保存,但输入的字符串是latin-9编码的,会出错,可以用/l
修饰符强制perl按照本地化设定的规则解析正则表达式的含义
use v5.14;
my $OE = chr(0xBC);
$_ = <STDIN>;
if(/$OE/li){
print "Found $OE";
}
3. 行首和行末锚位
行首和字符串首是不一样的,没有/m
的话,^
和$
的行为和\A
、\z
一样
4. 绑定操作符 =~
正则表达式的默认匹配目标文本是$_
,如果要指定匹配某个变量中的文本,可以使用绑定操作符
my $some_other = "I dream of betty rubble";
if ($some_other =~ /\brub/){
print "Aye, there's the rub.\n";
}
除非while循环的条件表达式中只有整行输入操作符(<STDIN>),否则输入行不会自动存入$_
绑定操作符的优先级非常高,不需要用圆括号括住模式匹配表达式
my $likes_perl = <STDIN> =~ /\byes\b/i;
5. 捕获变量
正则表达式中出现的圆括号一般都会触发正则引擎捕捉匹配到的字符串。
捕获组会把匹配括号中模式的字符串保存到相应的变量,有多少个圆括号,就有多少个捕获变量
每个捕获组包含的是原始字符串中的内容,不是模式本身
可以在匹配时通过反向引用来获取这些捕获的内容,也可以在匹配操作符结束后,用对应的捕获变量取得捕获的内容
由于捕获变量保存的是字符串,所以捕获变量实际上是标量变量
捕获变量的命名形式:$1
或者$2
变量$4
的意思就是模式中第4对括号所捕获的字符串内容,这个内容和模式运行期间所表示的反向引用\4
所表示的内容是一样的,而$4
则是模式匹配结束后得到的捕获内容的索引
$_ = "Hello there, neighbor";
if(/\s[a-zA-Z]+,/){ # 捕获空白字符和逗号自减的单词
print "the word was $1\n"; # 打印 the word was there
}
$_ = "Hello there, neighbor";
if(/(\S+) (\S+), (\S+)/){
print "words were $1 $2 $3\n"; # 打印 words were Hello there neighbor
}
有时候得到的捕获变量可能是空的,当给出的字符串不符合模式要求时,捕获变量可能会是空字符串
my $dino = "I fear that I'll be extinct after 1000 years.";
if($dino =~ /([0-9]*) years/){
print "That said '$1' years.\n"; # $1 为1000
}
my $dino = "I fear that I'll be extinct after a few million years.";
if($dino =~ /([0-9]*) years/){
print "That said '$1' years.\n"; # $1 为空字符串
}
空字符串并不等同于未定义字符串,若模式中有3个或者更少的圆括号,那么$4
的值就是undef