推荐答案
贪婪匹配和非贪婪匹配是正则表达式中两种不同的匹配策略。
贪婪匹配会尽可能多地匹配符合模式的字符。它会尝试匹配整个字符串,如果匹配失败,则会回溯,尝试匹配较短的字符串,直到找到一个匹配为止。默认情况下,正则表达式的量词(如 *, +, ?, {m,n})都是贪婪的。
非贪婪匹配也称懒惰匹配,会尽可能少地匹配符合模式的字符。它会尝试匹配尽可能短的字符串,只有在当前匹配无法满足整个模式时,才会继续匹配后面的字符。非贪婪匹配是通过在量词后面加上 ? 来实现的,例如 *?, +?, ??, {m,n}?。
本题详细解读
贪婪匹配
- 工作原理: 贪婪匹配在尝试匹配时,会先尽可能多地向后匹配字符,直到无法再匹配为止。
- 回溯: 如果后续的匹配失败,正则表达式引擎会回溯,减少匹配的数量,再尝试匹配。这个过程可能会消耗大量的计算资源,尤其是在处理长字符串时。
- 默认行为: 正则表达式的量词默认都是贪婪的,如
*,+,{n,m}等。 - 示例: 假设我们有一个字符串
"aaaabb",使用正则表达式a+b进行匹配。贪婪匹配会先尝试匹配所有a,即aaaa,然后发现后面需要b,但是下一个字符是b,所以匹配到aaaab,得到结果aaaab。
非贪婪匹配
- 工作原理: 非贪婪匹配在尝试匹配时,会尽可能少地向后匹配字符。它总是先尝试匹配最短的字符串。
- 最小匹配: 它会尝试匹配最短的符合条件的字符序列。
?符号: 通过在量词后面添加?来启用非贪婪模式,如*?,+?,{n,m}?。- 示例: 还是字符串
"aaaabb",这次使用正则表达式a+?b进行匹配。非贪婪匹配会尝试匹配最少的a,即匹配一个a后发现后面是一个b,所以匹配成功,得到结果ab。 如果使用a+?b在"aaaabb"中进行全局匹配,则结果是ab和ab
贪婪与非贪婪的差异对比
| 特性 | 贪婪匹配 | 非贪婪匹配 |
|---|---|---|
| 匹配策略 | 尽可能多地匹配 | 尽可能少地匹配 |
| 量词 | 默认行为: *, +, ?, {m,n} |
使用?后缀: *?, +?, ??, {m,n}? |
| 回溯 | 可能会发生回溯 | 减少回溯次数 |
| 匹配结果 | 可能匹配较长的字符串 | 通常匹配较短的字符串 |
| 适用场景 | 查找最长的匹配,默认行为 | 提取特定的子串,需要精确控制匹配长度 |
实际应用场景
- HTML解析:
- 贪婪匹配: 使用
<.*>可能匹配到整个HTML文档,而不是单个标签。 - 非贪婪匹配: 使用
<.*?>匹配到的是单个 HTML 标签,例如<div>,</div>等。
- 贪婪匹配: 使用
- 提取数据:
- 贪婪匹配: 可能匹配到不想要的字符,例如使用
".*"匹配"123abc456",可能会全部匹配到 - 非贪婪匹配:可以更精确地提取目标数据,例如使用
".*?"匹配"123abc456", 匹配到的是"123"和abc和"456"
- 贪婪匹配: 可能匹配到不想要的字符,例如使用
JavaScript 中的使用示例
// www.javascriptcn.com code example const str = "aaaabb"; // 贪婪匹配 const greedyRegex = /a+b/; console.log(str.match(greedyRegex)[0]); // 输出: aaaab // 非贪婪匹配 const lazyRegex = /a+?b/; console.log(str.match(lazyRegex)[0]); // 输出: ab const str2 = "<div>abc</div><div>def</div>"; const greedyHtmlRegex = /<.*>/; console.log(str2.match(greedyHtmlRegex)[0]) // 输出 "<div>abc</div><div>def</div>" const lazyHtmlRegex = /<.*?>/g; console.log(str2.match(lazyHtmlRegex)); //输出 ["<div>", "</div>", "<div>", "</div>"]