如何使用Go协程结合正则表达式解析文本文件中的URL
解决方案:用Go协程+WaitGroup拆分文本搜索URL
先给你重构后的完整代码,解决文本拆分、协程任务分配和结果汇总的问题:
import ( "fmt" "os" "regexp" "sync" "strings" ) // worker函数:处理分配的文本块,提取URL并写入结果(带锁保证线程安全) func worker(textBlock string, re *regexp.Regexp, results *[]string, mu *sync.Mutex, wg *sync.WaitGroup) { defer wg.Done() // 提取当前文本块中的所有https链接 urls := re.FindAllString(textBlock, -1) if len(urls) == 0 { return } // 加锁写入结果,避免并发写入冲突 mu.Lock() *results = append(*results, urls...) mu.Unlock() } func main() { // 1. 一次性读取文件内容,避免每个协程重复IO filePath := "repitations" b, err := os.ReadFile(filePath) if err != nil { fmt.Printf("读取文件失败: %v\n", err) return } content := string(b) // 2. 拆分文本块:按换行拆分成行切片,避免截断URL textBlocks := strings.Split(content, "\n") workerCount := 3 // 自定义worker数量 blockCount := len(textBlocks) if blockCount == 0 { fmt.Println("文件内容为空") return } // 3. 初始化正则:只匹配https://开头的链接 re := regexp.MustCompile(`https://\S+`) // 4. 初始化结果容器和互斥锁(保证并发安全) var results []string var mu sync.Mutex var wg sync.WaitGroup // 5. 分配任务给worker:按平均分配的方式拆分文本块 blocksPerWorker := (blockCount + workerCount - 1) / workerCount // 向上取整 for i := 0; i < workerCount; i++ { start := i * blocksPerWorker end := start + blocksPerWorker if end > blockCount { end = blockCount } // 取出当前worker要处理的文本块,合并成字符串 block := strings.Join(textBlocks[start:end], "\n") wg.Add(1) go worker(block, re, &results, &mu, &wg) } // 等待所有worker完成 wg.Wait() // 输出汇总结果 fmt.Println("找到的所有https链接:") for _, url := range results { fmt.Println("-", url) } fmt.Printf("总计找到%d个链接\n", len(results)) }
关键改进点说明:
- 避免重复IO:只在main函数中读一次文件,所有worker共享内容,减少磁盘开销
- 合理文本拆分:按换行拆分文本,防止把一个完整的URL拆成两半,保证提取准确性
- 通用worker函数:不用写多个重复的Parser函数,通过参数传递任务,复用逻辑
- 线程安全的结果收集:用
sync.Mutex保护结果切片,避免协程并发写入时的竞态问题 - 灵活的worker数量:可以自定义
workerCount,根据文本大小调整协程数量 - 精准正则:调整正则为只匹配
https://开头的链接,符合需求
如果需要更精确的URL匹配(比如支持带端口、路径的标准URL格式),可以把正则改成更严谨的版本,比如:
re := regexp.MustCompile(`https://(?:www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b(?:[-a-zA-Z0-9()@:%_\+.~#?&//=]*)`)
内容的提问来源于stack exchange,提问作者Raptorik
相关产品推荐
相关产品推荐

