Perl 简明教程

Perl - Regular Expressions

正则表达式是由定义你要查看的模式或模式的字符串组成的。Perl 中正则表达式的语法与你会在支持正则表达式的其他程序中发现的语法非常类似,如 sedgrepawk

应用正则表达式的基本方法是使用模式绑定操作符 =~ 和 ! ~. 第一个操作符是测试和赋值操作符。

Perl 中有三个正则表达式操作符。

  1. 匹配正则表达式 - m//

  2. 替换正则表达式 - s///

  3. 转换正则表达式 - tr///

在每种情况下,正斜杠都充当你要指定的正则表达式 (regex) 的定界符。如果你习惯使用任何其他定界符,则可以在正斜杠处使用它。

The Match Operator

匹配操作符 m// 用于将字符串或语句与正则表达式进行匹配。例如,要将字符序列“foo”与标量 $bar 进行匹配,你可以使用如下的语句:

#!/usr/bin/perl

$bar = "This is foo and again foo";
if ($bar =~ /foo/) {
   print "First time is matching\n";
} else {
   print "First time is not matching\n";
}

$bar = "foo";
if ($bar =~ /foo/) {
   print "Second time is matching\n";
} else {
   print "Second time is not matching\n";
}

當以上程式執行時,會產生以下結果 −

First time is matching
Second time is matching

实际上,m// 的工作方式与 q// 操作符系列相同,你可以使用任何自然匹配字符组合来充当表达式的定界符。例如,m{}、m() 和 m>< 都是有效的。因此,上面的示例可以改写如下:

#!/usr/bin/perl

$bar = "This is foo and again foo";
if ($bar =~ m[foo]) {
   print "First time is matching\n";
} else {
   print "First time is not matching\n";
}

$bar = "foo";
if ($bar =~ m{foo}) {
   print "Second time is matching\n";
} else {
   print "Second time is not matching\n";
}

如果你使用正斜杠作为定界符,则可以将 m 从 m// 中省略,但对于所有其他定界符,你都必须使用 m 前缀。

请注意,整个匹配表达式,即 =~ 或 !~ 左边的表达式和匹配操作符,如果表达式匹配,则在标量上下文中返回 true。因此,语句:

$true = ($foo =~ m/foo/);

如果 $foo 匹配 regex,则将把 $true 设为 1,如果匹配失败,则将其设为 0。在列表上下文中,匹配返回任何分组表达式的内容。例如,当从时间字符串中提取小时、分钟和秒时,我们可以使用:

my ($hours, $minutes, $seconds) = ($time =~ m/(\d+):(\d+):(\d+)/);

Match Operator Modifiers

匹配操作符支持其自己的修饰符集。/g 修饰符允许进行全局匹配。/i 修饰符将使匹配不区分大小写。以下是修饰符的完整列表,

Sr.No.

Modifier & Description

1

i 使匹配不区分大小写。

2

m 指定如果字符串有换行符或回车符,则 ^ 和 $ 运算符将匹配换行符边界,而不是字符串边界。

3

o 只评估表达式一次。

4

s 允许使用 . 匹配换行符。

5

x 允许你使用表达式中的空格以提高清晰度。

6

g Globally finds all matches.

7

cg 允许在全局匹配失败后继续搜索。

Matching Only Once

还有更简单的匹配运算符版本 - ?PATTERN? 运算符。这基本上与 m// 运算符相同,除了它只在你每次调用 reset 之间在搜索的字符串中匹配一次。

例如,你可以用它来获取列表中的第一个和最后一个元素 −

#!/usr/bin/perl

@list = qw/food foosball subeo footnote terfoot canic footbrdige/;

foreach (@list) {
   $first = $1 if /(foo.*?)/;
   $last = $1 if /(foo.*)/;
}
print "First: $first, Last: $last\n";

當以上程式執行時,會產生以下結果 −

First: foo, Last: footbrdige

Regular Expression Variables

正则表达式变量包括 $ ,其中包含最后一个分组匹配匹配的任何内容; $& ,其中包含整个匹配的字符串; $` ,其中包含匹配字符串之前的所有内容; $' ,其中包含匹配字符串之后的所有内容。下面的代码演示了结果 −

#!/usr/bin/perl

$string = "The food is in the salad bar";
$string =~ m/foo/;
print "Before: $`\n";
print "Matched: $&\n";
print "After: $'\n";

當以上程式執行時,會產生以下結果 −

Before: The
Matched: foo
After: d is in the salad bar

The Substitution Operator

替换运算符 s/// 实际上只是匹配运算符的扩展,它允许你用一些新文本来替换匹配的文本。运算符的基本形式是 −

s/PATTERN/REPLACEMENT/;

PATTERN 是我们正在寻找的文本的正则表达式。REPLACEMENT 是我们希望用于替换找到的文本的文本或正则表达式的规范。例如,我们可以使用以下正则表达式将 dog 的所有出现替换为 cat

#/user/bin/perl

$string = "The cat sat on the mat";
$string =~ s/cat/dog/;

print "$string\n";

當以上程式執行時,會產生以下結果 −

The dog sat on the mat

Substitution Operator Modifiers

以下是替换运算符中使用的所有修饰符的列表。

Sr.No.

Modifier & Description

1

i 使匹配不区分大小写。

2

m 指定如果字符串有换行符或回车符,则 ^ 和 $ 运算符将匹配换行符边界,而不是字符串边界。

3

o 只评估表达式一次。

4

s 允许使用 . 匹配换行符。

5

x 允许你使用表达式中的空格以提高清晰度。

6

g 用替换文本替换找到的表达式的所有出现。

7

e 将替换内容评估为 Perl 语句,并将其返回值用作替换文本。

The Translation Operator

翻译类似于替换原理,但不同之处在于,翻译(或音译)不使用正则表达式对其替换值进行搜索。翻译运算符是 −

tr/SEARCHLIST/REPLACEMENTLIST/cds
y/SEARCHLIST/REPLACEMENTLIST/cds

翻译将 SEARCHLIST 中所有字符的所有出现替换为 REPLACEMENTLIST 中的相应字符。例如,使用我们在本章中一直使用的字符串“The cat sat on the mat.” −

#/user/bin/perl

$string = 'The cat sat on the mat';
$string =~ tr/a/o/;

print "$string\n";

當以上程式執行時,會產生以下結果 −

The cot sot on the mot.

也可以使用标准 Perl 范围,从而允许你通过字母或数字值指定字符范围。要更改字符串的大小写,你可以使用以下语法代替 uc 函数。

$string =~ tr/a-z/A-Z/;

Translation Operator Modifiers

以下是与翻译相关的运算符列表。

Sr.No.

Modifier & Description

1

c Complements SEARCHLIST.

2

d 删除找到但未替换的字符。

3

s Squashes duplicate replaced characters.

/d 修饰符删除匹配 SEARCHLIST 但在 REPLACEMENTLIST 中没有相应项的字符。例如 −

#!/usr/bin/perl

$string = 'the cat sat on the mat.';
$string =~ tr/a-z/b/d;

print "$string\n";

當以上程式執行時,會產生以下結果 −

b b   b.

最后一个修饰符 /s 删除了被替换的重复字符序列,所以 −

#!/usr/bin/perl

$string = 'food';
$string = 'food';
$string =~ tr/a-z/a-z/s;

print "$string\n";

當以上程式執行時,會產生以下結果 −

fod

More Complex Regular Expressions

您不必仅仅在固定字符串上进行匹配。事实上,您可以通过使用更复杂的正则表达式匹配您能梦想到的任何内容。这里有一个速查表 −

下表列出了 Python 中可用的正则表达式语法。

Sr.No.

Pattern & Description

1

^ Matches beginning of line.

2

$ Matches end of line.

3

. 匹配除换行符以外的任何单个字符。使用 m 选项允许它也匹配换行符。

4

[&#8230;&#8203;] 匹配方括号中的任何单个字符。

5

[^&#8230;&#8203;] 匹配方括号中没有的任何单个字符。

6

匹配前面的表达式出现 0 次或多次。

7

+ 匹配前面的表达式出现 1 次或多次。

8

? 匹配前面的表达式出现 0 次或 1 次。

9

{ n} 精确匹配前面的表达式出现 n 次。

10

{ n,} 匹配前面的表达式出现 n 次或多次。

11

{ n, m} 匹配前面的表达式至少出现 n 次,最多出现 m 次。

12

*a

{b}匹配 a 或 b。

13

\w Matches word characters.

14

\W Matches nonword characters.

15

\s 匹配空格。等效于 [\t\n\r\f]。

16

\S Matches nonwhitespace.

17

\d 匹配数字。等效于 [0-9]。

18

\D Matches nondigits.

19

\A Matches beginning of string.

20

\Z 匹配字符串的结尾。如果存在换行符,则匹配在换行符前。

21

\z Matches end of string.

22

\G 匹配上次匹配结束的位置。

23

\b 当不在括号中时,匹配单词边界。当在括号中时,匹配退格符(0x08)。

24

\B Matches nonword boundaries.

25

\n, \t, etc. 匹配换行符、回车符、制表符等。

26

\1…​\9 Matches nth grouped subexpression.

27

\10 如果前面的子表达式已经匹配,则匹配第 n 个分组的子表达式。否则则引用于字符代码的八进制表示。

28

[aeiou] 匹配给定集合中的单个字符

29

脱字符 ^ 匹配字符串的开头,元符号 $ 匹配字符串的结尾。这里有一些简要的示例。

# nothing in the string (start and end are adjacent)
/^$/

# a three digits, each followed by a whitespace
# character (eg "3 4 5 ")
/(\d\s) {3}/

# matches a string in which every
# odd-numbered letter is a (eg "abacadaf")
/(a.)+/

# string starts with one or more digits
/^\d+/

# string that ends with one or more digits
/\d+$/

我们来看另一个示例。

#!/usr/bin/perl

$string = "Cats go Catatonic\nWhen given Catnip";
($start) = ($string =~ /\A(.*?) /);
@lines = $string =~ /^(.*?) /gm;
print "First word: $start\n","Line starts: @lines\n";

當以上程式執行時,會產生以下結果 −

First word: Cats
Line starts: Cats When

Matching Boundaries

\b 与任何单词词边界匹配,如 \w 类和 \W 类之间的差异所定义的。因为 \w 包含单词的字符,\W 包含相反的字符,这通常意味着单词的结束。断言 \B 与任何不是单词词边界的位置匹配。例如 −

/\bcat\b/ # Matches 'the cat sat' but not 'cat on the mat'
/\Bcat\B/ # Matches 'verification' but not 'the cat on the mat'
/\bcat\B/ # Matches 'catatonic' but not 'polecat'
/\Bcat\b/ # Matches 'polecat' but not 'catatonic'

Selecting Alternatives

| 字符与 Perl 中的标准或按位 OR 运算相同。它指定正则表达式或组内的交替匹配。例如,要在表达式中匹配“cat”或“dog”,您可以使用以下内容 −

if ($string =~ /cat|dog/)

您可以将表达式的各个元素组合在一起,以支持复杂的匹配。可以通过两个单独的测试来搜索两个人的姓名,如下所示 −

if (($string =~ /Martin Brown/) ||  ($string =~ /Sharon Brown/))

This could be written as follows

if ($string =~ /(Martin|Sharon) Brown/)

Grouping Matching

从正则表达式的角度来看,除了可能前者稍显清楚外,并没有区别。

$string =~ /(\S+)\s+(\S+)/;

and

$string =~ /\S+\s+\S+/;

但是,分组的好处在于它允许我们从正则表达式中提取一个序列。分组以它们在原始字符串中出现的顺序返回列表。例如,在以下片段中,我们从字符串中提取了小时、分钟和秒。

my ($hours, $minutes, $seconds) = ($time =~ m/(\d+):(\d+):(\d+)/);

除了这种直接方法,匹配的组还可以使用特殊变量 $x 获得,其中 x 是正则表达式中组的编号。因此,我们可以将前面的示例重写如下 −

#!/usr/bin/perl

$time = "12:05:30";

$time =~ m/(\d+):(\d+):(\d+)/;
my ($hours, $minutes, $seconds) = ($1, $2, $3);

print "Hours : $hours, Minutes: $minutes, Second: $seconds\n";

當以上程式執行時,會產生以下結果 −

Hours : 12, Minutes: 05, Second: 30

在替换表达式中使用组时,可以在替换文本中使用 $x 语法。因此,我们可以使用此来重新设置日期字符串的格式 −

#!/usr/bin/perl

$date = '03/26/1999';
$date =~ s#(\d+)/(\d+)/(\d+)#$3/$1/$2#;

print "$date\n";

當以上程式執行時,會產生以下結果 −

1999/03/26

The \G Assertion

\G 断言允许你继续从前一次匹配发生的位置进行搜索。例如,在以下代码中,我们使用了 \G,以便我们可以搜索到正确的位置,然后提取一些信息,而不必创建一个更加复杂、单一的正则表达式 −

#!/usr/bin/perl

$string = "The time is: 12:31:02 on 4/12/00";

$string =~ /:\s+/g;
($time) = ($string =~ /\G(\d+:\d+:\d+)/);
$string =~ /.+\s+/g;
($date) = ($string =~ m{\G(\d+/\d+/\d+)});

print "Time: $time, Date: $date\n";

當以上程式執行時,會產生以下結果 −

Time: 12:31:02, Date: 4/12/00

\G 断言实际上只是 pos 函数的元符号等价形式,因此在正则表达式调用之间你可以继续使用 pos,甚至可以通过将 pos 用作 lvalue 子例程,来修改 pos(因此还有 \G)的值。

Regular-expression Examples

Literal Characters

Sr.No.

Example & Description

1

Perl Match "Perl".

Character Classes

Sr.No.

Example & Description

1

[Pp]ython Matches "Python" or "python"

2

rub[ye] Matches "ruby" or "rube"

3

[aeiou] 匹配任何一个小写元音

4

[0-9] 匹配任何数字;与 [0123456789] 相同

5

[a-z] 匹配任何小写 ASCII 字母

6

[A-Z] 匹配任何大写 ASCII 字母

7

[a-zA-Z0-9] 匹配以上任意一个

8

[^aeiou] 匹配除小写元音之外的任何内容

9

[^0-9] 匹配除数字之外的任何内容

Special Character Classes

Sr.No.

Example & Description

1

. 匹配除了换行符之外的任何字符

2

\d Matches a digit: [0-9]

3

\D Matches a nondigit: [^0-9]

4

\s 匹配一个空白字符:[空格 \t\r\n\f]

5

\S Matches nonwhitespace: [^ \t\r\n\f]

6

\w 匹配一个单独的单词字符:[A-Za-z0-9_]

7

\W 匹配一个非单词字符:[^A-Za-z0-9_]

Repetition Cases

Sr.No.

Example & Description

1

ruby? 匹配 "rub" 或 "ruby":y 是可选的

2

ruby 匹配 "rub" 加 0 个或多个 y

3

ruby+ 匹配 "rub" 加 1 个或多个 y

4

\d{3} Matches exactly 3 digits

5

\d{3,} 匹配 3 个或更多位数字

6.

\d{3,5} 匹配 3、4 或 5 个数字

Nongreedy Repetition

这匹配最少重复数量−

Sr.No.

Example & Description

1

<.>* Greedy repetition: matches "<python>perl>"

2

&lt;. ?*Nongreedy: 在 "<python>perl>" 中匹配 "<python>"

Grouping with Parentheses

Sr.No.

Example & Description

1

\D\d+ No group: + 重复\d

2

(\D\d)+ 分组: + 重复\ D\d 对

3

([Pp]ython(, )?)+ 匹配 "Python", "Python, python, python" 等

Backreferences

这再次匹配先前的匹配组——

Sr.No.

Example & Description

1

([Pp])ython&\1ails Matches python&pails or Python&Pails

2

(['"])[^\1] \1*单引号或双引号字符串。\1 匹配第 1 个组匹配的内容。\2 匹配第 2 个组匹配的内容,依此类推。

Alternatives

Sr.No.

Example & Description

1

*python

perl* Matches "python" or "perl"

2

*rub(y

le))* Matches "ruby" or "ruble"

3

*Python(!+

Anchors

此需要指定匹配位置。

Sr.No.

Example & Description

1

^Python 匹配字符串或内部行开头处的“Python”

2

Python$ 匹配字符串或行结尾处的“Python”

3

\APython 匹配字符串开头处的“Python”

4

Python\Z 匹配字符串结尾处的“Python”

5

\bPython\b 在单词边界处匹配“Python”

6

\brub\B \B是非单词边界:匹配 "rube" 和 "ruby" 中的 "rub",但不单独匹配

7

Python(?=!) 在后面带有感叹号的情况下,匹配“Python”

8

Python(?!!) 在后面不带有感叹号的情况下,匹配“Python”

Special Syntax with Parentheses

Sr.No.

Example & Description

1

R(?#comment) 匹配 "R"。所有其他内容均为注释

2

R(?i)uby Case-insensitive while matching "uby"

3

R(?i:uby) Same as above

4

*rub(?:y