ZetCode

Golang Regexp.FindAllStringIndex

最后修改于 2025 年 4 月 20 日

本教程解释了如何在 Go 中使用 Regexp.FindAllStringIndex 方法。我们将介绍它的功能并提供实际示例。

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

Regexp.FindAllStringIndex 方法返回输入字符串中模式的所有连续匹配项的切片。每次匹配都表示为一个两元素整数切片。

基本 FindAllStringIndex 示例

FindAllStringIndex 最简单的用法是查找单词的所有匹配项。这里我们定位字符串中 "go" 的所有出现。

basic_find.go
package main

import (
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile(`go`)
    text := "go learn go, go golang"
    
    matches := re.FindAllStringIndex(text, -1)
    fmt.Println(matches) // [[0 2] [8 10] [13 15]]
}

该方法返回一个切片数组,其中每个内部切片包含匹配项的开始和结束索引。第二个参数 -1 表示查找所有匹配项。

查找多个单词的出现

此示例演示了在字符串中查找多个不同单词。我们搜索 "cat" 或 "dog" 的所有出现。

multi_word.go
package main

import (
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile(`cat|dog`)
    text := "I have a cat and a dog. My cat likes my dog."
    
    matches := re.FindAllStringIndex(text, -1)
    for _, match := range matches {
        fmt.Printf("Found %q at %d-%d\n", 
            text[match[0]:match[1]], match[0], match[1])
    }
}

交替运算符 | 匹配 "cat" 或 "dog"。我们打印每次匹配及其在原始字符串中的位置。

查找电子邮件位置

我们可以使用 FindAllStringIndex 在文本中定位电子邮件地址。此示例显示了如何查找它们的位置。

email_positions.go
package main

import (
    "fmt"
    "regexp"
)

func main() {
    pattern := `[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}`
    re := regexp.MustCompile(pattern)
    text := "Contact us at info@example.com or support@company.org"
    
    matches := re.FindAllStringIndex(text, -1)
    for _, match := range matches {
        fmt.Println("Email found at positions:", match[0], "to", match[1])
        fmt.Println("Email:", text[match[0]:match[1]])
    }
}

该模式匹配标准的电子邮件格式。我们从文本中提取位置和实际的电子邮件地址。

限制匹配数量

FindAllStringIndex 的第二个参数可以限制返回的匹配数量。在这里,我们只查找前两个数字。

limit_matches.go
package main

import (
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile(`\d+`)
    text := "100 200 300 400 500"
    
    // Find first two number matches
    matches := re.FindAllStringIndex(text, 2)
    fmt.Println(matches) // [[0 3] [4 7]]
}

我们不传递 -1 来查找所有匹配项,而是传递 2 来只获取前两个匹配项。该方法在找到指定数量的匹配项后停止搜索。

查找重叠匹配项

默认情况下,匹配项不重叠。此示例展示了如何使用前瞻断言查找重叠匹配项。

overlapping.go
package main

import (
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile(`(?=(\d\d\d))`)
    text := "12345"
    
    matches := re.FindAllStringIndex(text, -1)
    for _, match := range matches {
        fmt.Println("Match at:", match[0], "to", match[1])
        fmt.Println("Triplet:", text[match[0]:match[0]+3])
    }
}

前瞻断言 (?=...) 允许查找所有可能的 3 位数字序列。此技术对于查找文本中的重叠模式很有用。

查找单词边界

此示例演示了如何使用单词边界标记查找整个单词及其位置。

word_boundaries.go
package main

import (
    "fmt"
    "regexp"
)

func main() {
    re := regexp.MustCompile(`\b\w+\b`)
    text := "The quick brown fox jumps"
    
    matches := re.FindAllStringIndex(text, -1)
    for i, match := range matches {
        word := text[match[0]:match[1]]
        fmt.Printf("Word %d: %q at %d-%d\n", i+1, word, match[0], match[1])
    }
}

\b 标记确保我们只匹配整个单词。我们打印每个单词及其在原始字符串中的位置。

处理空匹配

在某些情况下,FindAllStringIndex 可能会返回空匹配。此示例显示了如何正确处理它们。

empty_matches.go
package main

import (
    "fmt"
    "regexp"
)

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

a* 模式匹配零个或多个 'a',这会导致空匹配。我们通过比较开始和结束索引来检查空匹配。

来源

Go regexp 包文档

本教程通过实际的模式匹配和位置查找示例,涵盖了 Go 中的 Regexp.FindAllStringIndex 方法。

作者

我的名字是 Jan Bodnar,我是一名充满热情的程序员,拥有丰富的编程经验。我自 2007 年以来一直在撰写编程文章。迄今为止,我已撰写了 1400 多篇文章和 8 本电子书。我在教学编程方面拥有十多年的经验。

列出所有 Go 教程