正则表达式实践

347 阅读2分钟

1. 贪婪模式和非贪婪模式

在正则表达式中,贪婪模式非贪婪模式的区别在于匹配字符时的 “贪心程度”。这两种模式主要影响重复元字符(如 *+?{n,})的行为。

核心区别

模式语法匹配逻辑
贪婪.*尽可能多地匹配字符(直到无法匹配为止)
非贪婪.*?尽可能少地匹配字符(一旦匹配就停止)

深入解释

1. 贪婪模式(默认行为)

  • 语法*+?{n,}(无后缀)。

  • 逻辑:从当前位置开始,尽可能多地匹配字符,直到无法继续匹配为止。

  • 示例
    正则 a.*c 匹配 a 和 c 之间的任意字符(贪婪模式):

    plaintext

    输入:ababc
    匹配:ababc(最长可能的字符串)
    

    解释:.* 会先匹配整个 babc,但由于末尾必须是 c,因此最终匹配 ababc

2. 非贪婪模式(懒惰匹配)

  • 语法*?+???{n,}?(添加 ? 后缀)。

  • 逻辑:从当前位置开始,尽可能少地匹配字符,一旦满足后续模式就立即停止。

  • 示例
    正则 a.*?c 匹配 a 和 c 之间的任意字符(非贪婪模式):

    plaintext

    输入:ababc
    匹配:abc(最短可能的字符串)
    

    解释:.*? 先匹配空字符串,但后续需要 c,因此逐步扩展匹配到 ab,直到遇到第一个 c 为止。

实战对比

场景 1:提取 HTML 标签内容

  • 输入<p>Hello</p><p>World</p>
  • 贪婪模式(正则:<p>(.*)</p>):
    匹配结果:<p>Hello</p><p>World</p>
    问题:.* 会吞掉中间的 </p><p>,导致匹配整个字符串。
  • 非贪婪模式(正则:<p>(.*?)</p>):
    匹配结果 1:<p>Hello</p>
    匹配结果 2:<p>World</p>
    正确提取两个标签的内容。

场景 2:提取引号内的内容

  • 输入"apple" "banana"
  • 贪婪模式(正则:"(.*)"):
    匹配结果:"apple" "banana"
    问题:.* 匹配到最后一个引号,导致跨越多组内容。
  • 非贪婪模式(正则:"(.*?)"):
    匹配结果 1:"apple"
    匹配结果 2:"banana"
    正确提取每组引号内的内容。

何时用哪种模式?

  • 贪婪模式:当需要匹配最长的可能字符串时(如提取整个 HTML 块)。
  • 非贪婪模式:当需要匹配最短的可能字符串时(如分割多个子串、提取特定标记内的内容)。

总结

  • 贪婪模式.* 像 “贪吃蛇”,尽可能多吃字符,直到满足整个正则。
  • 非贪婪模式.*? 像 “谨慎的食客”,吃到第一个满足条件的位置就停下。