1. 简单模式
匹配 key 的内容,只要把 key 的内容写在一对斜线 ( / ) 中即可:
$_ = "yabba dabba doo";
if (/abba/) {
say "It matched the string 'abba'";
}
2. Unicode 模式
a. 匹配包含特定属性的字符
\p{PROPERTY}
匹配属于空白符的字符,包括但不限于 空格,制表符,回车等:
if(/\p{Space}/) {
say "The string has some whitespace.\n";
}
b. 匹配不包含特定属性的字符(注意这里 P 是大写)
\P{PROPERTY}
3. 元字符
元字符 | 2 |
---|---|
点号 (.) | 匹配任意一个字符 |
星号(*) | 匹配前一个条目 零次或多次 |
加号(+) | 匹配前一个条目 至少一次 |
问号(?) | 匹配前一个条目 零次或一次 |
反斜线 | 转义 |
竖线(|) | 或(OR),择一匹配 |
方括号([]) | 字符集,只匹配单个字符 |
a. 点号(.) 是用于匹配任意一个字符的通配符,注意不包括换行符(\n)。
$_ = "betty";
if (/bet.y/) {
say "It matched!";
}
如果只想匹配点号本身,在点号前面加上反斜线转义即可:
$_ = "Mr.Smith";
if (/\./) {
say "The string has at least a dot.";
}
b. 星号(*) 用来匹配前面的条目零次或者多次。
可以这样理解,星号的符号表示正是数学运算中的乘法(times),可以乘以零次,也可以乘以一二三四五六次等等。
参看下面代码👇:
@_ = qw/ac abc abbc abbbbbbbbbbbbbbc adc/;
foreach (@_) {
if (/ab*c/) {
# 匹配 "ac"、"abc"、"abbc"、"abbbbbbbbbbbbbbc"
# 不匹配 "adc"
say "$_ matched!";
}
}
星号(*)前一个条目不仅仅可以是一个字符,也可以是其他元符号,比如点号(.),修改上方代码如下:
foreach (@_) {
if (/a.*c/) {
# 字符串 "adc" 也匹配上了
}
}
c. 加号(+) 匹配前一个条目至少一次。
@_ = ('a.dog', 'a dog', 'a dog', 'a dog');
foreach (@_) {
# 匹配 "a" 和 "dog" 之间用只包含空格的字符串隔开的字符串
if (/a +dog/) {
# do something
}
}
d. 问号(?) 用于匹配前一个条目出现零次或者一次。
@_ = qw/bamm-bamm bammbamm bamm--bamm/;
foreach (@_) {
# 匹配 'bamm-bamm' 和 'bammbamm'
# 但不匹配 'bamm--bamm'
if (/bamm-?bamm/) {
# do something
}
}
e. 或(|) 表示要么匹配左边的内容,要么匹配右边的内容。
$_ = "fred";
if (/fred|barney|betty/) {
# ...
}
f. 方括号([ ]) ,列出一组可能出现的字符,并匹配其中的一个。
字符集通常不会单独使用,而是作为完整模式的一部分和其他元字符配合使用。
$_ = "The HAL-9000 requires authorization to continue.";
if (/HAL-[0-9]+/) {
# 匹配至少一个数字
}
注意连字符(-)的使用,在字符集([ ])外它是个普通的字符,所以 “HAL-” 表示普通的短横线,但是在 [0-9] 它表示指定范围。如果需要在字符集中匹配连字符,需要加反斜线 (\):
if (/[+\-*\/]/) {
# ...
}
字符集搭配脱字符(^)使用,可以指定字符集范围之外的内容。
@_ = qw/an am and arm/;
foreach (@_) {
if (/a[^nm]/) {
# 匹配 "arm"
# 不匹配 "an"、"am" 和 "and"
}
}
4. 模式分组
星号(*),问号(?),加号(+) 都是针对前一个条目进行匹配的,这里的条目,不仅仅只是字符或者 点号(.),也可以是字符串比如 “abba”。
在正则表达式中用 圆括号(()) 对字符串分组,使之成为一个条目:
@_ = qw/bingbong bingbing bongbong/;
foreach (@_) {
# 匹配条目 “bing” 零次或者 n 次
# 这里匹配了 “bingbong” 和 “bongbong”
# 不匹配 “bingbing”
if (/(bing)*bong/) {
# do something
}
}
如果想要在表达式中重用条目,可以使用捕获组。对捕获组的引用称为反向引用,表示为 \N ,其中 N 表示组的索引,起始序号为 1。
@_ = ("yabba dabba", "yabbp dabbc", "yabcc dabcc");
foreach (@_) {
# ‘d’ 后面跟着四个字符
# 这四个字符跟 ‘y’ 后面的四个字符是一样的
# 匹配 "yabba dabba", "yabcc dabcc"
# 不匹配 "yabbp dabbc"
if (/y(....) d\1/) {
# do something
}
}
多个捕获组也是可以的:
@_ = qw/yabba dabba doo/;
foreach (@_) {
# 匹配 "yabba","dabba"
# 不匹配 "doo"
if (/(.)(.)\2\1/) {
# do something
}
}
Perl 5.10 开始支持反向引用的另一种写法 \g{N},这种写法可以很好地消除反向引用与模式直接量部分的二义性:
$_ = "aa11bb";
if (/(.)\111/) {
# 是 \1,\11 还是 \111 呢?
# 按照 perl 的逻辑,这里应该是 \111
# 但是并没有那么多的分组
# 低版本会直接报错,而高版本则永远无法得到正确的结果
print "It matched!\n";
}
而采用 \g{N} 的写法,就简单明了多了:
$_ = "aa11bb";
if (/(.)\g{1}11/) {
# do something
}
\g{N} 写法的另一个好处是可以使用负数,用来指定相对反向引用。
$_ = "xaa11bb";
if (/(.)\g{-1}11/) {
# ...
}
使用相对方向引用的好处是,如果模式中引用的内容前面需要追加其他内容,那么绝对编号的反向引用会失效,而相对方向的反向引用却不会。
$_ = "xaa11bb";
if (/(.)(.)\g{-1}11/) {
# 依然可以匹配 "xaa11bb"
}