ZetCode

Golang Regexp.FindAllSubmatchIndex

最后修改于 2025 年 4 月 20 日

本教程将介绍如何在 Go 语言中使用 Regexp.FindAllSubmatchIndex 方法。我们将涵盖其功能并提供实际示例。

一个 正则表达式 是一个定义搜索模式的字符序列。它用于在字符串中进行模式匹配。

Regexp.FindAllSubmatchIndex 方法返回一个整数切片组成的切片。每个整数切片代表匹配项和子匹配项的位置。

基本的 FindAllSubmatchIndex 示例

FindAllSubmatchIndex 最简单的用法是查找字符串中的所有匹配项及其位置。这里我们定位简单的单词匹配。

basic_find.go
package main

import (
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile(`go`)
    text := "go golang go go"
    
    indices := re.FindAllSubmatchIndex([]byte(text), -1)
    for _, match := range indices {
        fmt.Printf("Found at %d-%d: %s\n", 
            match[0], match[1], text[match[0]:match[1]])
    }
}

我们编译模式 "go",并在文本中查找所有出现的地方。每次匹配都会返回输入字节切片中的开始和结束位置。

查找子匹配项的位置

此示例演示了捕获组的位置。我们将提取日期组件及其确切位置。

submatch_positions.go
package main

import (
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile(`(\d{4})-(\d{2})-(\d{2})`)
    text := "Date: 2025-04-20, Another: 2026-05-21"
    
    matches := re.FindAllSubmatchIndex([]byte(text), -1)
    for _, match := range matches {
        fmt.Println("Full match:", text[match[0]:match[1]])
        fmt.Println("Year:", text[match[2]:match[3]])
        fmt.Println("Month:", text[match[4]:match[5]])
        fmt.Println("Day:", text[match[6]:match[7]])
    }
}

该模式有三个捕获组。每次匹配都会返回八个整数:完整匹配项以及每个组的开始/结束位置对。

查找重叠匹配项

使用先行断言时,FindAllSubmatchIndex 可以查找重叠匹配项。这显示了所有可能的 3 位数字序列。

overlapping.go
package main

import (
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile(`(?=(\d{3}))`)
    text := "12345"
    
    matches := re.FindAllSubmatchIndex([]byte(text), -1)
    for _, match := range matches {
        start, end := match[2], match[3]
        fmt.Printf("Found at %d-%d: %s\n", 
            start, end, text[start:end])
    }
}

先行断言会查找后面跟着三个数字的所有位置。每次匹配都会返回先行断言的位置和捕获的组。

提取键值对

此示例展示了如何解析键值对并获取其确切位置。我们将处理一个简单的配置文件字符串。

key_value.go
package main

import (
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile(`(\w+)=("[^"]*"|\S+)`)
    text := `name="John Doe" age=30 city="New York"`
    
    matches := re.FindAllSubmatchIndex([]byte(text), -1)
    for _, match := range matches {
        key := text[match[2]:match[3]]
        value := text[match[4]:match[5]]
        fmt.Printf("Key: %s (at %d-%d), Value: %s (at %d-%d)\n",
            key, match[2], match[3], 
            value, match[4], match[5])
    }
}

该模式匹配键和值,支持带引号的值。我们提取每个组件的内容和位置。

查找嵌套结构

这个高级示例演示了如何解析嵌套结构。我们将提取 HTML 标签及其属性和位置。

nested.go
package main

import (
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile(`<(\w+)(\s+([^>]*))?>`)
    text := `<div class="header"><p align="center">Hello</p></div>`
    
    matches := re.FindAllSubmatchIndex([]byte(text), -1)
    for _, match := range matches {
        fmt.Println("Full tag:", text[match[0]:match[1]])
        fmt.Println("Tag name:", text[match[2]:match[3]])
        if match[4] != -1 {
            fmt.Println("Attributes:", text[match[6]:match[7]])
        }
    }
}

该模式匹配带有可选属性的 HTML 标签。我们检查 -1 以处理未参与匹配的可选组。

处理空匹配

此示例展示了 FindAllSubmatchIndex 如何处理空匹配。我们将处理可能包含零长度匹配项的字符串。

empty_matches.go
package main

import (
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile(`a*`)
    text := "baaab"
    
    matches := re.FindAllSubmatchIndex([]byte(text), -1)
    for i, match := range matches {
        if match[0] == match[1] {
            fmt.Printf("Match %d: empty at position %d\n", i, match[0])
        } else {
            fmt.Printf("Match %d: %q at %d-%d\n", 
                i, text[match[0]:match[1]], match[0], match[1])
        }
    }
}

该模式匹配零个或多个 'a'。空匹配会返回相等的开始和结束位置。此行为对于某些算法很重要。

性能注意事项

在处理大型文本时,请考虑限制匹配的数量。此示例说明了如何控制结果的大小。

limit_matches.go
package main

import (
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile(`\d+`)
    text := "1 22 333 4444 55555 666666"
    
    // Find first 3 matches
    matches := re.FindAllSubmatchIndex([]byte(text), 3)
    for _, match := range matches {
        fmt.Println(text[match[0]:match[1]])
    }
}

第二个参数限制了返回的匹配数量。使用此参数可以防止可能多次匹配的模式导致过多的内存使用。

来源

Go regexp 包文档

本教程通过查找匹配项及其位置的实际示例,介绍了 Go 语言中的 Regexp.FindAllSubmatchIndex 方法。

作者

我叫 Jan Bodnar,是一名热情的程序员,拥有丰富的编程经验。我从 2007 年开始撰写编程文章。迄今为止,我已撰写了 1400 多篇文章和 8 本电子书。我在教授编程方面拥有十多年的经验。

列出所有 Go 教程