正則表達式基礎
Perl 正則表達式(Regex)是文本處理的核心利器。模式由分隔符包圍:/pattern/,支持豐富的元字符、量詞、錨點、分組捕獲等特性。
核心語法速查表
| 語法 | 說明 | 示例匹配 |
. | 任意單字符(除換行符) | /a.c/ 匹配 "abc", "axc" |
\d | 數字 [0-9] | /\d+/ 匹配 "123" |
\D | 非數字 [^0-9] | |
\w | 單詞字符 [a-zA-Z0-9_] | |
\W | 非單詞字符 | |
\s | 空白字符 [ \t\r\n\f] | |
\S | 非空白字符 | |
* | 0 次或多次 | /ab*c/ 匹配 "ac", "abc", "abbc" |
+ | 1 次或多次 | /ab+c/ 匹配 "abc", "abbc" |
? | 0 次或 1 次 | /ab?c/ 匹配 "ac", "abc" |
{m} | 恰好 m 次 | /\d{3}/ 匹配 "123" |
{m,n} | m 到 n 次 | /\d{2,4}/ |
{m,} | 至少 m 次 | /\d{2,}/ |
[...] | 字符類(任一) | /[aeiou]/ |
[^...] | 否定字符類 | /[^0-9]/ |
^ | 行首錨點 | /^start/ |
$ | 行尾錨點 | /end$/ |
\b | 單詞邊界 | /\bword\b/ |
\B | 非單詞邊界 | |
(...) | 捕獲分組 | /(\d+)-(\d+)/ $1, $2 |
(?:...) | 非捕獲分組 | 僅分組不捕獲 |
| | 或運算 | /cat|dog/ |
\1, \2... | 反向引用 | /(\w+)\s+\1/ 重複單詞 |
匹配操作符 =~ 與 !~
my $var = "hello world";
my $result = $var =~ /world/; # 真值(匹配成功)
my $nomatch = $var !~ /java/; # 真值(不匹配)
# 在條件判斷中直接使用
if ($question =~ /please/) {
print "Thank you for being polite!\n";
} else {
print "That was not very polite!\n";
}
模式修飾符
| 修飾符 | 說明 | 示例 |
i | 忽略大小寫 | /perl/i 匹配 "Perl", "PERL" |
g | 全局匹配(所有) | while (/pattern/g) { ... } |
m | 多行模式(^$ 匹配行首尾) | /^line/m |
s | 單行模式(. 匹配換行符) | /a.b/s 匹配 "a\nb" |
x | 擴展模式(忽略模式空白、允許註釋) | /\d{2} # 註釋 /x |
o | 只編譯一次(變量插值) | /$var/o |
替換操作符 s///
my $string = "abc123def";
$string =~ s/123/456/; # $string = "abc456def"
# 使用捕獲變量
$string =~ s/(\d+)/[$1]/; # 數字加方括號
# 修飾符
$string =~ s/pattern/replacement/g; # 全局替換
$string =~ s/pattern/replacement/i; # 忽略大小寫
$string =~ s/pattern/replacement/e; # replacement 作為表達式求值
$string =~ s/(\w+)/uc($1)/e; # 單詞大寫
轉譯操作符 tr///
my $string = "abcdefghicba";
$string =~ tr/abc/def/; # a->d, b->e, c->f
# 結果: "defdefghifed"
# 修飾符
$string =~ tr/A-Z/a-z/; # 大寫轉小寫
$string =~ tr/0-9/ /c; # 非數字轉空格 (c: 補集)
$string =~ tr/\t //d; # 刪除制表符和空格 (d: 刪除)
$string =~ tr/0-9/ /cs; # 非數字壓縮為單個空格 (s: 壓縮)
擴展模式與註釋
# x 修飾符允許空白和註釋
my $regex = qr/
^ # 行首
(\d{4}) # 年份捕獲 $1
- # 分隔符
(\d{2}) # 月份捕獲 $2
- # 分隔符
(\d{2}) # 日期捕獲 $3
$ # 行尾
/x;
"2024-01-15" =~ $regex; # 匹配成功,$1=2024, $2=01, $3=15
前瞻與後顧斷言
| 語法 | 名稱 | 說明 |
(?=pattern) | 正向前瞻 | 後面匹配 pattern(不消耗字符) |
(?!pattern) | 負向前瞻 | 後面不匹配 pattern |
(?<=pattern) | 正向後顧 | 前面匹配 pattern(固定寬度) |
(? | 負向後顧 | 前面不匹配 pattern |
# 只匹配數字後面的字母
"abc123def" =~ /(?<=\d)[a-z]+/; # 匹配 "def"
# 匹配非數字開頭的單詞
"123 abc" =~ /(?
實戰經典案例
1. 變量名合法性校驗
if ($varname =~ /^\$[A-Za-z][_0-9a-zA-Z]*$/) {
print "$varname is a legal scalar variable\n";
} elsif ($varname =~ /^@[A-Za-z][_0-9a-zA-Z]*$/) {
print "$varname is a legal array variable\n";
}
2. 數字格式驗證(十進制/十六進制)
if ($number =~ /^-?\d+$|^-?0[xX][\da-fA-F]+$/) {
print "$number is a legal integer\n";
}
3. 日期格式提取(YYYY-MM-DD)
my $date_regex = qr/(\d{4})-(\d{2})-(\d{2})/;
if ($input =~ $date_regex) {
my ($year, $month, $day) = ($1, $2, $3);
print "Year: $year, Month: $month, Day: $day\n";
}
4. 郵箱地址提取
my @emails = $text =~ /([\w.+-]+@[\w-]+\.[\w.-]+)/g;
5. HTML 標籤移除
$html =~ s/<[^>]+>//g; # 簡單移除(不處理屬性中 >)
性能優化技巧
- 預編譯:
qr/pattern/ 編譯一次,多次復用
- 避免過度回溯:
.* 貪婪匹配導致災難性回溯,用 .*? 或具體字符類
- 錨點優化:
^/$/\b 快速定位
- 具體字符類:
[a-z] 比 . 快
- 非捕獲分組:
(?:...) 避免捕獲開銷
常見陷阱
| 陷阱 | 錯誤代碼 | 正確代碼 |
| 貪婪匹配過度 | /<.*>/ 匹配 "bd" 為整串 | /<[^>]*>/ 或 /<.*?>/ |
| 變量插值未轉義 | /$user_input/ 特殊字符被解釋 | /\Q$user_input\E/ 或 quotemeta |
| 分組編號錯誤 | 嵌套分組導致 $1/$2 混亂 | 使用 (?:...) 非捕獲、或命名捕獲 (?<name>...) |
| 修飾符位置錯誤 | s/pattern/replacement/gi (i 在 g 後) | s/pattern/replacement/ig (順序任意但推薦標準) |
總結
Perl 正則表達式功能強大、語法豐富,是文本處理的瑞士軍刀。掌握核心元字符、量詞、錨點、分組捕獲、修飾符、替換/轉譯操作、前瞻後顧斷言與性能優化技巧,能高效解決複雜的文本解析、驗證、提取、轉換需求。實戰中注意貪婪匹配陷阱、變量轉義、預編譯復用,編寫可維護的高性能正則。