Golang Regexp.FindAllIndex
最后修改于 2025 年 4 月 20 日
本教程解释了如何在 Go 中使用 Regexp.FindAllIndex
方法。我们将通过实际示例介绍其功能。
一个 正则表达式 是一个定义搜索模式的字符序列。它用于在字符串中进行模式匹配。
Regexp.FindAllIndex
方法返回输入字节切片中模式的所有连续匹配项的切片。每个匹配项由一个两元素的整数切片表示。
基本 FindAllIndex 示例
FindAllIndex
最简单的用法是查找单词的所有出现。这里我们定位文本中所有的“go”实例。
basic_findall.go
package main import ( "fmt" "regexp" ) func main() { text := []byte("go is good, go is great, go is awesome") re := regexp.MustCompile(`go`) matches := re.FindAllIndex(text, -1) for _, match := range matches { fmt.Printf("Found 'go' at %d-%d\n", match[0], match[1]) } }
该方法返回 [开始, 结束] 索引对的切片。每对索引表示输入文本中的一个匹配位置。
查找多个模式
FindAllIndex
可以查找多个不同的模式。此示例在文本中定位“cat”和“dog”。
multiple_patterns.go
package main import ( "fmt" "regexp" ) func main() { text := []byte("cat dog bird cat dog") re := regexp.MustCompile(`cat|dog`) matches := re.FindAllIndex(text, -1) for i, match := range matches { word := string(text[match[0]:match[1]]) fmt.Printf("Match %d: %s at %d-%d\n", i+1, word, match[0], match[1]) } }
交替运算符 | 匹配任一模式。我们使用返回的索引提取匹配的单词。
限制匹配数量
第二个参数控制返回多少个匹配项。这里我们限制为前两个匹配项。
limit_matches.go
package main import ( "fmt" "regexp" ) func main() { text := []byte("one two three four five six") re := regexp.MustCompile(`\w+`) matches := re.FindAllIndex(text, 2) for _, match := range matches { word := string(text[match[0]:match[1]]) fmt.Println(word) } }
将 n 设置为 2 只返回前两个匹配项。使用 -1 查找所有匹配项。
查找重叠匹配项
默认情况下,匹配项不重叠。此示例演示了如何使用前瞻查找重叠匹配项。
overlapping.go
package main import ( "fmt" "regexp" ) func main() { text := []byte("ababab") re := regexp.MustCompile(`(?=(aba))`) matches := re.FindAllIndex(text, -1) for _, match := range matches { // Note: match[0] == match[1] for zero-width matches fmt.Printf("Found at %d-%d: %s\n", match[0], match[0]+3, text[match[0]:match[0]+3]) } }
前瞻断言 (?=...) 允许查找重叠模式。每个匹配项具有相等的开始和结束索引。
查找所有电子邮件索引
这个实际示例查找文本中所有的电子邮件地址及其位置。
email_indices.go
package main import ( "fmt" "regexp" ) func main() { text := []byte(`Contact us at info@example.com or support@company.com`) re := regexp.MustCompile(`[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}`) matches := re.FindAllIndex(text, -1) for _, match := range matches { email := string(text[match[0]:match[1]]) fmt.Printf("Email %s at %d-%d\n", email, match[0], match[1]) } }
该模式匹配标准的电子邮件格式。我们提取了电子邮件本身及其在文本中的确切位置。
处理空匹配
空匹配项需要特殊处理。此示例演示了它们的行为。
empty_matches.go
package main import ( "fmt" "regexp" ) func main() { text := []byte("a,,b,c,,") re := regexp.MustCompile(`,`) matches := re.FindAllIndex(text, -1) fmt.Println("All comma positions:") for _, match := range matches { fmt.Printf("%d-%d\n", match[0], match[1]) } // Handling empty fields between commas fields := re.Split(string(text), -1) fmt.Println("\nFields:") for i, field := range fields { fmt.Printf("%d: %q\n", i, field) } }
空匹配项显示为零长度范围。它们对于分割字符串同时保留空字段很有用。
性能注意事项
对于大型文本,请考虑使用 FindAllIndex
配合字节切片而不是字符串以获得更好的性能。
performance.go
package main import ( "fmt" "regexp" "time" ) func main() { // Generate large text var text []byte for i := 0; i < 10000; i++ { text = append(text, "abc123 "...) } re := regexp.MustCompile(`\d+`) start := time.Now() matches := re.FindAllIndex(text, -1) elapsed := time.Since(start) fmt.Printf("Found %d matches in %s\n", len(matches), elapsed) fmt.Printf("First match at %d-%d\n", matches[0][0], matches[0][1]) }
使用字节切片可避免字符串转换。这可以显著提高大型输入的性能。
来源
本教程通过模式匹配和索引检索的实际示例,介绍了 Go 中的 Regexp.FindAllIndex
方法。