在 Perl 中,正则表达式的量词 *, +, ?, {n,m} 默认是 贪婪的 (greedy):它们会捕获与模式匹配的最大可能字符数。
在量词后添加 ? 会将其变为 非贪婪的 (lazy 或 non-greedy):它会捕获最少可能的字符数,以使整个正则表达式匹配。
my $str = 'foo <bar> baz <quux>'; $str =~ /<.*>/; # 捕获 '<bar> baz <quux>'
my $str = 'foo <bar> baz <quux>'; $str =~ /<.*?>/; # 捕获 '<bar>'
贪婪表达式可能会“吃掉”比预期更多的内容,例如在解析 HTML 和其他嵌套结构时!
字符串
<a><b><c>的两个正则表达式/<(.*)>/和/<(.*?)>/有什么区别?
回答:
/<(.*)>/ (贪婪)会捕获最大块 — 匹配:<a><b><c>/<(.*?)>/ (非贪婪) — 仅捕获第一个组:<a>示例:
my $s = '<a><b><c>'; $s =~ /<(.*)>/; # $1: 'a><b><c' $s =~ /<(.*?)>/; # $1: 'a'
故事
在一个导入新闻标题的应用程序中,程序员试图解析字符串
<title>新闻</title>中标签的名称,使用了/\<(.*)\>/。结果正则表达式捕获了<第一个和>最后之间的整行,而不是所需的元素。当出现嵌套标签时,错误被发现。
故事
在一个逻辑解析器中,为了提取引用字符串,使用的模板
/"(.*)"/意外地捕获了第一个和最后一个引号之间的所有内容。结果标记错误分解,直到模板被替换为/"(.*?)"/。
故事
在一个带引号的 CSV 自动解析器中,贪婪地编写的模板出现了错误,导致多个列合并为一个。该解析器的故障只在大数据集上显现出来 — 对模板的非贪婪修改解决了这个问题。