
本文介绍使用 Go 标准库 bufio.Scanner 按单词扫描输入流,并精确统计目标单词出现频次的完整实现,包含正确用法、关键细节说明及可运行示例。
本文介绍使用 go 标准库 `bufio.scanner` 按单词扫描输入流,并精确统计目标单词出现频次的完整实现,包含正确用法、关键细节说明及可运行示例。
在 Go 中实现单词频次统计,核心在于利用 bufio.Scanner 的分词能力配合逐词比对。bufio.Scanner 默认按行扫描,但通过调用 scanner.Split(bufio.ScanWords) 可切换为以空白符(空格、制表符、换行等)为边界进行单词切分,每次 scanner.Scan() 返回一个单词片段,其内容可通过 scanner.Text() 获取。
以下是经过修正与优化的完整函数实现:
func Occurrences(word string, r io.Reader) (int, error) {
scanner := bufio.NewScanner(r)
scanner.Split(bufio.ScanWords) // ✅ 正确设置为单词扫描模式
wordCount := 0
for scanner.Scan() {
if scanner.Text() == word {
wordCount++
}
}
return wordCount, scanner.Err() // ✅ 必须返回 scanner.Err() 以捕获扫描过程中的 I/O 错误(如读取中断、编码问题等)
}⚠️ 关键注意事项:
-
不要传入
strings.NewReader(s):原代码中strings.NewReader(s)的写法是错误的——s是io.Reader类型,而strings.NewReader()接收的是string。应直接将r(即原始io.Reader)传给bufio.NewScanner()。 -
区分大小写:
scanner.Text() == word是严格大小写敏感匹配。如需忽略大小写,可统一转为小写后比较:if strings.ToLower(scanner.Text()) == strings.ToLower(word) { ... } -
返回类型建议用
int而非uint:Go 生态惯例及标准库(如strings.Count)均使用有符号整数;uint在错误处理和边界场景(如计数溢出调试)中反而不友好。 -
错误处理不可省略:循环结束后必须调用
scanner.Err(),否则 I/O 错误(例如网络流中断、文件权限不足)将被静默忽略。
✅ 使用示例:
func main() {
input := strings.NewReader("hello world hello golang hello")
count, err := Occurrences("hello", input)
if err != nil {
log.Fatal(err)
}
fmt.Printf("'%s' appears %d times\n", "hello", count) // 输出:'hello' appears 3 times
}该方案简洁、高效且符合 Go 的惯用风格,适用于文件、网络响应、标准输入等任意 io.Reader 数据源,是文本单词统计任务的标准实践。

















