【正则表达式】非捕获组 (?: ... )的使用方法和必要性

定义

非捕获组,用 (?: ... ) 表示。这意味着它将匹配括号内的内容,但是不会将匹配的内容存储到内存中供后续引用。

这对于那些我们想要作为一个整体处理,但是又不需要单独捕获其内容的情况非常有用。

 

举例

假设我们有一个字符串 abc123def,并且我们想要匹配其中的数字,同时忽略其他部分。如果我们使用以下正则表达式:

(a)(bc)(123)(def)

这个表达式会捕获四个不同的组:abc123def。如果我们只是关心中间的数字 123 而不是其他部分,那么我们可以把不需要的部分放入非捕获组中:

(?:a)(?:bc)(123)(?:def)

这样只有数字 123 会被捕获。如果我们使用这个正则表达式去查找匹配项,只有 123 会被返回为捕获组。

 

与普通捕获组相比

当你使用普通捕获组 (...) 时,正则表达式引擎会自动存储所有捕获组的结果。如果正则表达式中有大量的捕获组,即使你并不需要所有这些结果,也会占用额外的内存和计算资源。
使用非捕获组 (?: ... ) 可以避免这种不必要的开销,提高性能。具体来说:

  1. 内存节省:

    • 正则表达式引擎需要为每个捕获组分配内存空间来存储匹配的结果。
    • 使用非捕获组 (?: ... ) 可以避免这部分内存分配,从而节省内存。
  2. 性能优化:

    • 捕获组的创建和管理涉及到额外的操作,包括存储和检索匹配结果。
    • 使用非捕获组可以减少这些操作,从而提高正则表达式的执行速度。

 

使用场景

第一次接触到这个概念的人可能会想:不需要处理那不要用()捕获不就行了吗。

但是使用非捕获组有一些好处。

 

首先,非捕获组是一个捕获组加上“?:”,那它首先有一些普通捕获组有的好处:

  1. 分组匹配:括号可以用来确保某些部分作为一个整体进行匹配。
  2. 优先级控制:括号可以用来控制匹配的优先级,特别是当有嵌套的模式时。
  3. 结构清晰性:括号可以使复杂的正则表达式更具可读性和可维护性。
  4. 重复利用:有时你可能需要在同一个表达式中多次使用相同的模式,括号可以帮助你实现这一点。

如果说2、3、4点都是一些非必要的使用情况,那么将某部分作为一个整体进行匹配在一些情况下可能是必须的。

 

比如:需求是匹配一行参数文本,捕获其出现的参数,但其中有些参数可能不存在。

{ stream: "data_stream", pcp: 1, interface: "eth0" }
{ vlan: 10, stream: "data_stream", pcp: 1, interface: "eth0" }

比如上面这两行文本,第一行就比第二行少了vlan这个参数。

这时候,先将匹配 vlan: 10 的这部分使用括号写成一个整体,然后在括号后面跟上一个问号,就可以表示这个整体模式可以存在也可以不存在:

(?:\s*vlan:\s*(?<VID>\d+),?)?

这个表达式表示:

  • 整个模式 \s*vlan:\s*(?<VID>\d+),? 是可选的。
  • 如果这个模式存在,它将匹配 vlan: 后面跟着一个或多个空白字符、一个或多个数字(这些数字被捕获为 VID)、一个可选的逗号。

 

总结一下:

如果只在这里使用普通捕获组:

  • 将这段内容作为一个整体,加上?即可表示个整体模式可以存在也可以不存在
  • 结构清晰明了

 

在非捕获组内设置了普通捕获组的写法,相比起普通捕获组:

  • 非捕获组减少了不必要的内存分配和正则表达式引擎的额外操作
  • 捕获的内容更精确,简化后续的逻辑处理

 

这样看来,这就是比较合理、高效的一种写法。

posted @ 2024-09-05 17:40  ban_boi  阅读(77)  评论(0编辑  收藏  举报