正則表達式比此處所介紹的主題要大得多,確信你理解了這些概念。對于教程, 可以參閱?[perlrequick](http://perldoc.perl.org/perlrequick.html)?或?[perlretut](http://perldoc.perl.org/perlretut.html)。而權威的文檔,則能夠參閱?[perlre](http://perldoc.perl.org/perlre.html)。
## 匹配和替換返回數量
`m//`?和?`s///`?操作符分別返回匹配或替換的數目。你既可以直接使用該數目, 也可以檢查其真值。
~~~
if ( $str =~ /Diggle|Shelley/ ) {
print "We found Pete or Steve!\n";
}
if ( my $n = ($str =~ s/this/that/g) ) {
print qq{Replaced $n occurrence(s) of "this"\n};
}
~~~
## 不要在未檢查匹配成功的情況下使用捕獲變量
除非匹配成功,捕獲變量?`$1`?等是無效的,并且它們不會被清理。
~~~
# BAD: Not checked, but at least it "works".
my $str = 'Perl 101 rocks.';
$str =~ /(\d+)/;
print "Number: $1"; # Prints "Number: 101";
# WORSE: Not checked, and the result is not what you'd expect
$str =~ /(Python|Ruby)/;
print "Language: $1"; # Prints "Language: 101";
~~~
你必須檢查匹配的返回值:
~~~
# GOOD: Check the results
my $str = 'Perl 101 rocks.';
if ( $str =~ /(\d+)/ ) {
print "Number: $1"; # Prints "Number: 101";
}
if ( $str =~ /(Python|Ruby)/ ) {
print "Language: $1"; # Never gets here
}
~~~
## 常用匹配選項
### `/i`:不區分大小寫
### `/g`:匹配多次
~~~
$var = "match match match";
while ($var =~ /match/g) { $a++; }
print "$a\n"; # prints 3
$a = 0;
$a++ foreach ($var =~ /match/g);
print "$a\n"; # prints 3
~~~
### `/m`:更改?`^`?和?`$`?的意義
正常情況下,`^`?意為字符串的開頭,而?`$`?為字符串的結尾。`/m`?使它們分別意為行首和行尾。
~~~
$str = "one\ntwo\nthree";
@a = $str =~ /^\w+/g; # @a = ("one");
@b = $str =~ /^\w+/gm; # @b = ("one","two","three")
~~~
不管是否有?`/m`,使用?`\A`?和?`\z`?來匹配字符串的開頭和結尾。`\Z`?除了會忽略最后的換行之外,與?`\z`?相同,
### `/s`:使?`.`?也匹配換行
~~~
$str = "one\ntwo\nthree\n";
$str =~ /^(.{8})/s;
print $1; # prints "one\ntwo\n"
~~~
## 捕獲變量?`$1`?及之友
捕獲括號對的內容被存儲到數字變量中。括號從左到右分配:
~~~
my $str = "abc";
$str =~ /(((a)(b))(c))/;
print "1: $1 2: $2 3: $3 4: $4 5: $5\n";
# prints: 1: abc 2: ab 3: a 4: b 5: c
~~~
捕獲括號及變量的數目沒有上限。
## 利用?`?:`?避免捕獲
如果括號后緊接著?`?:`,那么該分組不會被捕獲。在你不想保存匹配的內容時 會有用:
~~~
my $str = "abc";
$str =~ /(?:a(b)c)/;
print "$1\n"; # prints "b"
~~~
## 利用?`/x`?選項使正則表達式更易讀
如果你在使用正則表達式時玩了些花樣,那么為它寫注釋。你可以使用?`/x`?選項達到目的。
丑陋的龐然大物:
~~~
my ($num) = $ARGV[0] =~ m/^\+?((?:(?<!\+)-)?(?:\d*.)?\d+)$/x;
~~~
使用?`/x`?允許的空白和注釋更可讀:
~~~
my ($num) =
$ARGV[0] =~ m/^ \+? # An optional plus sign, to be discarded
( # Capture...
(?:(?<!\+)-)? # a negative sign, if there's no plus behind it,
(?:\d*.)? # an optional number, followed by a point if a decimal,
\d+ # then any number of numbers.
)$/x;
~~~
除非被轉義,空白和注釋將被去除。
## 利用?`\Q`?和?`\E`?自動引起正則表達式
這會自動轉義正則表達式的元字符。不會轉義?`$`?符號。
~~~
my $num = '3.1415';
print "ok 1\n" if $num =~ /\Q3.14\E/;
$num = '3X1415';
print "ok 2\n" if $num =~ /\Q3.14\E/;
print "ok 3\n" if $num =~ /3.14/;
~~~
輸出:
~~~
ok 1
ok 3
~~~
## 對?`s///`?使用?`/e`?選項來執行代碼
這將允許任意代碼替換正則表達式中的字符串。
~~~
my $str = "AbCdE\n";
$str =~ s/(\w)/lc $1/eg;
print $str; # prints "abcde"
~~~
必要時使用?`$1`?及之友。
## 了解何時使用?`study`
`study`?在多數情況下都無用。它所做的是創建一個每個單字節字符首次出現在字符串中 的位置的表。這意味著如果你有 1,000 個字符長的字符串,你要尋找由一個常量字符開頭 的各種字符串,匹配器可以立即跳轉到正確的位置。例如:
~~~
"This is a very long [... 900 characters skipped...] string that I have here,
ending at position 1000"
~~~
現在,如果你要匹配正則表達式?`/Icky/`,匹配器將試圖尋找第一個匹配的字母?`I`。在 找到它之前得掃描前面的 900+ 個字符。但?`study`?創建了一個 256 個字節第一次出現 的地方的表。所以掃描器能夠立即跳轉到那個位置來開始匹配。
> 譯注:這里沒有考慮到多字節字符。
## 使用?`re => debug`?調試正則表達式
~~~
-Mre=debug
~~~