编程全栈开发者

解释 Perl 中正则表达式量词的贪婪和非贪婪处理原理。这如何影响字符串解析?举例说明一些微妙之处和非标准行为。

用 Hintsage AI 助手通过面试

回答。

在 Perl 中,正则表达式的量词 *, +, ?, {n,m} 默认是 贪婪的 (greedy):它们会捕获与模式匹配的最大可能字符数。

在量词后添加 ? 会将其变为 非贪婪的 (lazynon-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 自动解析器中,贪婪地编写的模板出现了错误,导致多个列合并为一个。该解析器的故障只在大数据集上显现出来 — 对模板的非贪婪修改解决了这个问题。