Perl正则量词用法:匹配次数怎么写才不踩坑

你是不是也遇到过这样的情况:想用ref="/tag/2034/" style="color:#2B406D;font-weight:bold;">Perl匹配一串数字,结果要么多匹配了,要么根本没匹配上?问题很可能出在量词上。Perl里那几个看似简单的符号——*+?{n,m},用错一个,整个正则就跑偏。

先搞清三个基本量词

* 表示“零次或多次”,比如 \d* 能匹配空字符串、"0"、"123",甚至整行都没数字也能通过;
+ 是“一次或多次”,\d+ 至少要有一个数字,空的就不行;
? 表示“零次或一次”,常用来处理可选内容,比如匹配带不带括号的电话号码:\(?(\d{3})\)?-?(\d{4})

别小看花括号,它最靠谱

想精确控制次数?直接上 {n}{n,}{n,m}
比如验证身份证后四位:\d{4}
匹配6~12位密码:[a-zA-Z0-9_]{6,12}
找连续3个以上字母:[a-zA-Z]{3,}

贪婪 vs 懒惰:一个问号的区别

默认所有量词都是“贪婪”的——能多吃就多吃。比如对字符串 "abc123def456ghi",用 \d+ 会分别匹配 "123""456";但换成 \d+?(加个?),它就变成懒惰模式,只取第一个数字就停。

实战例子:提取HTML里的图片地址

假设有一段:<img src="logo.png" alt="logo"><img src="banner.jpg">
想只拿 src 的值,写成 src="(.*?)" 就比 src="(.*)" 安全得多——后者会从第一个 " 一直吃到末尾的最后一个 ",把两段都吞进去。

my $html = '<img src="logo.png" alt="logo"><img src="banner.jpg">';
while ($html =~ /src="(.*?)"/g) {
    print "Found: $1\n";
}

常见陷阱提醒

a* 时,别忘了它能匹配零长度,可能造成无限循环;
.* 前先想想有没有更具体的替代,比如 [^\n]*\S+
\w+ 看似方便,但在中文环境里会漏掉汉字,真要匹配中文得加 \p{Han}+ 或明确写 [\x{4e00}-\x{9fff}]+