perlrequick - Perl 正则表达式快速入门
本页介绍了在 Perl 中理解、创建和使用正则表达式(“regexes”)的入门知识。
本页假设您已经了解一些知识,例如什么是“模式”以及使用它们的语法。如果您不了解,请参阅 perlretut。
最简单的正则表达式只是一个词,或者更一般地说,是一串字符。由一个词组成的正则表达式匹配包含该词的任何字符串
"Hello World" =~ /World/; # matches
在这个语句中,World
是一个正则表达式,而 //
包含 /World/
告诉 Perl 在字符串中搜索匹配项。运算符 =~
将字符串与正则表达式匹配关联起来,如果正则表达式匹配则产生真值,如果正则表达式不匹配则产生假值。在我们的例子中,World
与 "Hello World"
中的第二个词匹配,所以表达式为真。这个想法有几个变体。
像这样的表达式在条件语句中很有用
print "It matches\n" if "Hello World" =~ /World/;
可以使用 !~
运算符反转匹配的意义
print "It doesn't match\n" if "Hello World" !~ /World/;
正则表达式中的字面字符串可以用变量替换
$greeting = "World";
print "It matches\n" if "Hello World" =~ /$greeting/;
如果你要匹配 $_
,可以省略 $_ =~
部分
$_ = "Hello World";
print "It matches\n" if /World/;
最后,匹配的默认分隔符 //
可以通过在前面添加一个 'm'
来更改为任意分隔符
"Hello World" =~ m!World!; # matches, delimited by '!'
"Hello World" =~ m{World}; # matches, note the matching '{}'
"/usr/bin/perl" =~ m"/perl"; # matches after '/usr/bin',
# '/' becomes an ordinary char
正则表达式必须完全匹配字符串的一部分,才能使语句为真
"Hello World" =~ /world/; # doesn't match, case sensitive
"Hello World" =~ /o W/; # matches, ' ' is an ordinary char
"Hello World" =~ /World /; # doesn't match, no ' ' at end
Perl 将始终在字符串中最早可能的位置进行匹配
"Hello World" =~ /o/; # matches 'o' in 'Hello'
"That hat is red" =~ /hat/; # matches 'hat' in 'That'
并非所有字符都可以在匹配中“按原样”使用。一些字符,称为 **元字符**,被认为是特殊的,并保留用于正则表达式表示法。元字符是
{}[]()^$.|*+?\
可以通过在元字符前面加上反斜杠来匹配元字符的字面意义
"2+2=4" =~ /2+2/; # doesn't match, + is a metacharacter
"2+2=4" =~ /2\+2/; # matches, \+ is treated like an ordinary +
'C:\WIN32' =~ /C:\\WIN/; # matches
"/usr/bin/perl" =~ /\/usr\/bin\/perl/; # matches
在最后一个正则表达式中,正斜杠 '/'
也被反斜杠转义,因为它用于分隔正则表达式。
大多数元字符并不总是特殊的,而其他字符(例如分隔模式的字符)在各种情况下会变得特殊。这可能会令人困惑,并导致意外结果。 use re 'strict'
可以通知您潜在的陷阱。
不可打印的 ASCII 字符由 **转义序列** 表示。常见的例子有 \t
表示制表符,\n
表示换行符,\r
表示回车符。任意字节由八进制转义序列表示,例如 \033
,或十六进制转义序列表示,例如 \x1B
"1000\t2000" =~ m(0\t2) # matches
"cat" =~ /\143\x61\x74/ # matches in ASCII, but
# a weird way to spell cat
正则表达式主要被视为双引号字符串,因此变量替换有效
$foo = 'house';
'cathouse' =~ /cat$foo/; # matches
'housecat' =~ /${foo}cat/; # matches
对于上面所有的正则表达式,如果正则表达式在字符串中的任何位置匹配,则被认为是匹配。为了指定它应该匹配的位置,我们将使用 **锚点** 元字符 ^
和 $
。锚点 ^
表示在字符串的开头匹配,锚点 $
表示在字符串的结尾匹配,或者在字符串结尾的换行符之前匹配。一些例子
"housekeeper" =~ /keeper/; # matches
"housekeeper" =~ /^keeper/; # doesn't match
"housekeeper" =~ /keeper$/; # matches
"housekeeper\n" =~ /keeper$/; # matches
"housekeeper" =~ /^housekeeper$/; # matches
字符类允许在正则表达式中的特定位置匹配一组可能的字符,而不是单个字符。字符类有多种类型,但通常人们使用这个术语时,指的是本节中描述的类型,它们在技术上被称为“方括号字符类”,因为它们用方括号[...]
表示,其中包含要匹配的字符集。但为了与常用用法一致,我们将在下面省略“方括号”。以下是一些(方括号)字符类的示例
/cat/; # matches 'cat'
/[bcr]at/; # matches 'bat', 'cat', or 'rat'
"abc" =~ /[cab]/; # matches 'a'
在最后一个语句中,即使'c'
是类中的第一个字符,正则表达式可以匹配的最早位置是'a'
。
/[yY][eE][sS]/; # match 'yes' in a case-insensitive way
# 'yes', 'Yes', 'YES', etc.
/yes/i; # also match 'yes' in a case-insensitive way
最后一个示例显示了与'i'
修饰符的匹配,它使匹配不区分大小写。
字符类也有普通字符和特殊字符,但字符类内部的普通字符和特殊字符集与字符类外部的字符集不同。字符类的特殊字符是-]\^$
,并且使用转义匹配
/[\]c]def/; # matches ']def' or 'cdef'
$x = 'bcr';
/[$x]at/; # matches 'bat, 'cat', or 'rat'
/[\$x]at/; # matches '$at' or 'xat'
/[\\$x]at/; # matches '\at', 'bat, 'cat', or 'rat'
特殊字符'-'
在字符类中充当范围运算符,因此笨拙的[0123456789]
和[abc...xyz]
变为简洁的[0-9]
和[a-z]
/item[0-9]/; # matches 'item0' or ... or 'item9'
/[0-9a-fA-F]/; # matches a hexadecimal digit
如果'-'
是字符类中的第一个或最后一个字符,则它被视为普通字符。
特殊字符^
在字符类的第一个位置表示否定字符类,它匹配除方括号中的字符之外的任何字符。[...]
和[^...]
都必须匹配一个字符,否则匹配失败。然后
/[^a]at/; # doesn't match 'aat' or 'at', but matches
# all other 'bat', 'cat, '0at', '%at', etc.
/[^0-9]/; # matches a non-numeric character
/[a^]at/; # matches 'aat' or '^at'; here '^' is ordinary
Perl 有几个用于常见字符类的缩写。(这些定义是 Perl 在使用/a
修饰符的 ASCII 安全模式下使用的。否则,它们也可能匹配更多非 ASCII Unicode 字符。有关详细信息,请参阅"perlrecharclass 中的转义序列"。)
\d 是一个数字,表示
[0-9]
\s 是一个空白字符,表示
[\ \t\r\n\f]
\w 是一个单词字符(字母数字或 _),表示
[0-9a-zA-Z_]
\D 是一个否定的 \d;它表示除数字以外的任何字符
[^0-9]
\S 是一个否定的 \s;它表示任何非空白字符
[^\s]
\W 是一个否定的 \w;它表示任何非单词字符
[^\w]
句点 '.' 匹配除 "\n" 之外的任何字符
\d\s\w\D\S\W
缩写可以在字符类内部和外部使用。以下是一些正在使用的示例
/\d\d:\d\d:\d\d/; # matches a hh:mm:ss time format
/[\d\s]/; # matches any digit or whitespace character
/\w\W\w/; # matches a word char, followed by a
# non-word char, followed by a word char
/..rt/; # matches any two chars, followed by 'rt'
/end\./; # matches 'end.'
/end[.]/; # same thing, matches 'end.'
单词锚 \b
匹配单词字符和非单词字符\w\W
或\W\w
之间的边界
$x = "Housecat catenates house and cat";
$x =~ /\bcat/; # matches cat in 'catenates'
$x =~ /cat\b/; # matches cat in 'housecat'
$x =~ /\bcat\b/; # matches 'cat' at end of string
在最后一个示例中,字符串的结尾被视为单词边界。
对于自然语言处理(例如,将撇号包含在单词中),请改用 \b{wb}
"don't" =~ / .+? \b{wb} /x; # matches the whole string
我们可以使用交替元字符 '|'
匹配不同的字符串。要匹配 dog
或 cat
,我们形成正则表达式 dog|cat
。与之前一样,Perl 将尝试在字符串中尽早匹配正则表达式。在每个字符位置,Perl 将首先尝试匹配第一个备选方案 dog
。如果 dog
不匹配,Perl 将尝试下一个备选方案 cat
。如果 cat
也不匹配,则匹配失败,Perl 将移动到字符串中的下一个位置。一些例子
"cats and dogs" =~ /cat|dog|bird/; # matches "cat"
"cats and dogs" =~ /dog|cat|bird/; # matches "cat"
即使 dog
是第二个正则表达式中的第一个备选方案,cat
也能够在字符串中更早地匹配。
"cats" =~ /c|ca|cat|cats/; # matches "c"
"cats" =~ /cats|cat|ca|c/; # matches "cats"
在给定的字符位置,允许正则表达式匹配成功的第一个备选方案将是匹配的方案。这里,所有备选方案都在第一个字符串位置匹配,所以第一个匹配。
分组元字符 ()
允许将正则表达式的部分视为一个单元。正则表达式的部分通过将它们括在括号中来分组。正则表达式 house(cat|keeper)
表示匹配 house
后跟 cat
或 keeper
。以下是一些其他示例
/(a|b)b/; # matches 'ab' or 'bb'
/(^a|b)c/; # matches 'ac' at start of string or 'bc' anywhere
/house(cat|)/; # matches either 'housecat' or 'house'
/house(cat(s|)|)/; # matches either 'housecats' or 'housecat' or
# 'house'. Note groups can be nested.
"20" =~ /(19|20|)\d\d/; # matches the null alternative '()\d\d',
# because '20\d\d' can't match
分组元字符 ()
还允许提取匹配字符串的部分。对于每个分组,匹配的部分将进入特殊变量 $1
、$2
等。它们可以像普通变量一样使用
# extract hours, minutes, seconds
$time =~ /(\d\d):(\d\d):(\d\d)/; # match hh:mm:ss format
$hours = $1;
$minutes = $2;
$seconds = $3;
在列表上下文中,带有分组的匹配 /regex/
将返回匹配值的列表 ($1,$2,...)
。因此,我们可以将其改写为
($hours, $minutes, $second) = ($time =~ /(\d\d):(\d\d):(\d\d)/);
如果正则表达式中的分组是嵌套的,$1
获取具有最左侧开括号的分组,$2
获取下一个开括号,等等。例如,以下是一个复杂的正则表达式,以及它下面的匹配变量
/(ab(cd|ef)((gi)|j))/;
1 2 34
与匹配变量 $1
、$2
等相关联的是反向引用 \g1
、\g2
等。反向引用是匹配变量,可以在正则表达式内部使用
/(\w\w\w)\s\g1/; # find sequences like 'the the' in string
$1
、$2
等仅应在正则表达式之外使用,而 \g1
、\g2
等仅应在正则表达式内部使用。
量词 元字符 ?
、*
、+
和 {}
允许我们确定正则表达式中我们认为匹配的部分的重复次数。量词紧跟在我们要指定的字符、字符类或分组之后。它们具有以下含义
a?
= 匹配 'a' 1 或 0 次
a*
= 匹配 'a' 0 次或多次,即任意次数
a+
= 匹配 'a' 1 次或多次,即至少一次
a{n,m}
= 匹配至少 n
次,但不超过 m
次。
a{n,}
= 匹配至少 n
次或更多次
a{,n}
= 匹配 n
次或更少次
a{n}
= 匹配正好 n
次
以下是一些示例
/[a-z]+\s+\d*/; # match a lowercase word, at least some space, and
# any number of digits
/(\w+)\s+\g1/; # match doubled words of arbitrary length
$year =~ /^\d{2,4}$/; # make sure year is at least 2 but not more
# than 4 digits
$year =~ /^\d{ 4 }$|^\d{2}$/; # better match; throw out 3 digit dates
这些量词将尝试匹配尽可能多的字符串,同时仍然允许正则表达式匹配。因此我们有
$x = 'the cat in the hat';
$x =~ /^(.*)(at)(.*)$/; # matches,
# $1 = 'the cat in the h'
# $2 = 'at'
# $3 = '' (0 matches)
第一个量词 .*
尽可能多地获取字符串,同时仍然使正则表达式匹配。第二个量词 .*
没有剩余的字符串,因此它匹配 0 次。
关于匹配运算符,您可能还需要了解一些其他内容。全局修饰符 /g
允许匹配运算符在字符串中尽可能多次匹配。在标量上下文中,对字符串的连续匹配将使 /g
在匹配之间跳转,在它进行的过程中跟踪字符串中的位置。您可以使用 pos()
函数获取或设置位置。例如,
$x = "cat dog house"; # 3 words
while ($x =~ /(\w+)/g) {
print "Word is $1, ends at position ", pos $x, "\n";
}
打印
Word is cat, ends at position 3
Word is dog, ends at position 7
Word is house, ends at position 13
匹配失败或更改目标字符串将重置位置。如果您不希望在匹配失败后重置位置,请添加 /c
,如 /regex/gc
。
在列表上下文中,/g
返回匹配分组的列表,或者如果没有分组,则返回对整个正则表达式的匹配列表。所以
@words = ($x =~ /(\w+)/g); # matches,
# $word[0] = 'cat'
# $word[1] = 'dog'
# $word[2] = 'house'
搜索和替换使用 s/regex/replacement/modifiers
执行。replacement
是一个 Perl 双引号字符串,它用与 regex
匹配的内容替换字符串中的内容。运算符 =~
也用于将字符串与 s///
关联。如果与 $_
匹配,则可以删除 $_ =~
。如果匹配,s///
返回执行的替换次数;否则返回 false。以下是一些示例
$x = "Time to feed the cat!";
$x =~ s/cat/hacker/; # $x contains "Time to feed the hacker!"
$y = "'quoted words'";
$y =~ s/^'(.*)'$/$1/; # strip single quotes,
# $y contains "quoted words"
使用 s///
运算符,匹配的变量 $1
、$2
等立即可用于替换表达式。使用全局修饰符,s///g
将搜索并替换字符串中正则表达式的所有出现
$x = "I batted 4 for 4";
$x =~ s/4/four/; # $x contains "I batted four for 4"
$x = "I batted 4 for 4";
$x =~ s/4/four/g; # $x contains "I batted four for four"
非破坏性修饰符 s///r
会返回替换的结果,而不是修改 $_
(或任何使用 =~
绑定到替换的变量)。
$x = "I like dogs.";
$y = $x =~ s/dogs/cats/r;
print "$x $y\n"; # prints "I like dogs. I like cats."
$x = "Cats are great.";
print $x =~ s/Cats/Dogs/r =~ s/Dogs/Frogs/r =~
s/Frogs/Hedgehogs/r, "\n";
# prints "Hedgehogs are great."
@foo = map { s/[a-z]/X/r } qw(a b c 1 2 3);
# @foo is now qw(X X X 1 2 3)
评估修饰符 s///e
会在替换字符串周围包装一个 eval{...}
,并且评估结果将替换匹配的子字符串。以下是一些示例
# reverse all the words in a string
$x = "the cat in the hat";
$x =~ s/(\w+)/reverse $1/ge; # $x contains "eht tac ni eht tah"
# convert percentage to decimal
$x = "A 39% hit rate";
$x =~ s!(\d+)%!$1/100!e; # $x contains "A 0.39 hit rate"
最后一个示例表明 s///
可以使用其他分隔符,例如 s!!!
和 s{}{}
,甚至 s{}//
。如果使用单引号 s'''
,则正则表达式和替换将被视为单引号字符串。
split /regex/, string
将 string
分割成一个子字符串列表并返回该列表。正则表达式决定 string
相对于其分割的字符序列。例如,要将字符串分割成单词,请使用
$x = "Calvin and Hobbes";
@word = split /\s+/, $x; # $word[0] = 'Calvin'
# $word[1] = 'and'
# $word[2] = 'Hobbes'
要提取逗号分隔的数字列表,请使用
$x = "1.618,2.718, 3.142";
@const = split /,\s*/, $x; # $const[0] = '1.618'
# $const[1] = '2.718'
# $const[2] = '3.142'
如果使用空正则表达式 //
,则字符串将被分割成单个字符。如果正则表达式有分组,则生成的列表还包含来自分组的匹配子字符串
$x = "/usr/bin";
@parts = split m!(/)!, $x; # $parts[0] = ''
# $parts[1] = '/'
# $parts[2] = 'usr'
# $parts[3] = '/'
# $parts[4] = 'bin'
由于 $x 的第一个字符与正则表达式匹配,split
在列表之前添加了一个空的初始元素。
use re 'strict'
在 v5.22 中新增,这在编译正则表达式模式时应用比其他情况更严格的规则。它可以找到一些合法但可能不是你想要的东西。
参见 'strict' in re.
无。
这只是一个快速入门指南。有关正则表达式的更深入教程,请参见 perlretut,有关参考页,请参见 perlre.
版权所有 (c) 2000 Mark Kvale 保留所有权利。
本文件可以在与 Perl 本身相同的条款下分发。
作者要感谢 Mark-Jason Dominus、Tom Christiansen、Ilya Zakharevich、Brad Hughes 和 Mike Giroux 对他们所有有益的评论。