Golang Regexp.FindAllStringSubmatch
最后修改于 2025 年 4 月 20 日
本教程将介绍如何在 Go 中使用 Regexp.FindAllStringSubmatch
方法。我们将涵盖子匹配项提取,并提供实际示例。
一个 正则表达式 是一个定义搜索模式的字符序列。它用于在字符串中进行模式匹配。
Regexp.FindAllStringSubmatch
方法会在字符串中返回正则表达式的所有匹配项,包括子匹配项。每个匹配项都是一个字符串切片。
基本 FindAllStringSubmatch 示例
最简单的用法是从字符串中提取所有匹配项和子匹配项。在这里,我们在文本中查找日期。
package main import ( "fmt" "regexp" ) func main() { text := "Dates: 2025-04-20, 2025-05-15, 2025-06-10" re := regexp.MustCompile(`(\d{4})-(\d{2})-(\d{2})`) matches := re.FindAllStringSubmatch(text, -1) for _, match := range matches { fmt.Printf("Full: %s, Year: %s, Month: %s, Day: %s\n", match[0], match[1], match[2], match[3]) } }
该方法返回一个切片数组。每个内部切片包含完整的匹配项以及子匹配项。索引 0 始终是完整的匹配项。
提取键值对
此示例演示了如何使用命名捕获组从字符串中提取键值对。
package main import ( "fmt" "regexp" ) func main() { text := "name=John age=30 city=New York" re := regexp.MustCompile(`(\w+)=(\w+)`) matches := re.FindAllStringSubmatch(text, -1) for _, match := range matches { fmt.Printf("Key: %s, Value: %s\n", match[1], match[2]) } }
该模式捕获等号之前和之后的单词字符。每次匹配都包含完整的键值对以及分隔的组件。
查找 HTML 标签和属性
在这里,我们从字符串中提取 HTML 标签及其属性。这展示了更复杂的模式匹配。
package main import ( "fmt" "regexp" ) func main() { html := `<a href="https://example.com" title="Example">Link</a>` re := regexp.MustCompile(`<(\w+)([^>]*)>`) matches := re.FindAllStringSubmatch(html, -1) for _, match := range matches { fmt.Println("Tag:", match[1]) fmt.Println("Attributes:", match[2]) } }
该模式捕获标签名称和所有属性。请注意,使用正则表达式解析 HTML 对于复杂文档存在局限性。
提取多个电子邮件地址
此示例展示了如何从文本中提取多个电子邮件地址及其组件(使用子匹配项)。
package main import ( "fmt" "regexp" ) func main() { text := `Contact us at info@example.com or support@company.co.uk` re := regexp.MustCompile(`([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+)\.([a-zA-Z]{2,})`) matches := re.FindAllStringSubmatch(text, -1) for _, match := range matches { fmt.Println("Full email:", match[0]) fmt.Println("Username:", match[1]) fmt.Println("Domain:", match[2]) fmt.Println("TLD:", match[3]) fmt.Println() } }
每个电子邮件匹配项被分解为用户名、域名和顶级域组件。该模式匹配常见的电子邮件格式。
解析日志条目
日志文件通常包含可以用正则表达式提取的结构化数据。在这里,我们解析 Apache 日志条目。
package main import ( "fmt" "regexp" ) func main() { logEntry := `127.0.0.1 - frank [10/Oct/2025:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326` re := regexp.MustCompile(`^(\S+) (\S+) (\S+) \[([^\]]+)\] "(\S+) (\S+) (\S+)" (\d+) (\d+)$`) matches := re.FindAllStringSubmatch(logEntry, -1) for _, match := range matches { fmt.Println("IP:", match[1]) fmt.Println("User:", match[3]) fmt.Println("Date:", match[4]) fmt.Println("Method:", match[5]) fmt.Println("Path:", match[6]) fmt.Println("Status:", match[8]) fmt.Println("Size:", match[9]) } }
该模式捕获标准 Apache 日志条目的所有组件。每个组件都可以作为单独的子匹配项获取。
提取电话号码
此示例演示了如何从文本中提取各种格式的电话号码及其组件。
package main import ( "fmt" "regexp" ) func main() { text := `Call 555-1234 or (555) 987-6543 or 555.456.7890` re := regexp.MustCompile(`\(?(\d{3})\)?[-. ]?(\d{3})[-. ]?(\d{4})`) matches := re.FindAllStringSubmatch(text, -1) for _, match := range matches { fmt.Println("Full number:", match[0]) fmt.Println("Area code:", match[1]) fmt.Println("Exchange:", match[2]) fmt.Println("Line number:", match[3]) fmt.Println() } }
该模式处理几种常见的电话号码格式。子匹配项提取区号、交换号码和线路号码组件。
限制匹配数量
FindAllStringSubmatch 的第二个参数控制返回多少个匹配项。此示例显示了如何限制匹配项。
package main import ( "fmt" "regexp" ) func main() { text := "apple banana apple cherry apple date" re := regexp.MustCompile(`apple`) // Get all matches allMatches := re.FindAllStringSubmatch(text, -1) fmt.Println("All matches:", len(allMatches)) // Get first 2 matches limitedMatches := re.FindAllStringSubmatch(text, 2) fmt.Println("Limited matches:", len(limitedMatches)) }
负值返回所有匹配项。正数将结果限制为该数量的匹配项。这可以提高处理大型输入的性能。
来源
本教程通过实际示例演示了如何在 Go 中使用 Regexp.FindAllStringSubmatch
方法从字符串中提取子匹配项。