你是不是也遇到过这样的情况:想用ref="/tag/2034/" style="color:#E3A3CF;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}]+。