Word Count CLI in Go
A Go program that counts words from a file or stdin, printing the total and the five most frequent words in descending order.
Project
go-word-count-cli
Entry point: main.go
Install
go versionRun
go run main.go words.txtTest
go test ./...Expected output
Prints the total word count, then the top five words with counts, sorted by frequency then alphabetically.Dependencies
- go >=1.21
What it does
Reads the input, splits it into words on non-letter boundaries, lowercases them, and tallies counts in a map. It then sorts by count descending and by word ascending for stable output, printing the top five.
package main
import (
"bufio"
"fmt"
"os"
"sort"
"strings"
"unicode"
)
func words(r *bufio.Scanner) map[string]int {
counts := map[string]int{}
for r.Scan() {
for _, w := range strings.FieldsFunc(r.Text(), func(r rune) bool { return !unicode.IsLetter(r) }) {
counts[strings.ToLower(w)]++
}
}
return counts
}
func main() {
var in *os.File
if len(os.Args) > 1 {
f, err := os.Open(os.Args[1])
if err != nil {
fmt.Fprintln(os.Stderr, "cannot open file:", err)
os.Exit(1)
}
defer f.Close()
in = f
} else {
in = os.Stdin
}
scanner := bufio.NewScanner(in)
counts := words(scanner)
total := 0
for _, n := range counts {
total += n
}
keys := make([]string, 0, len(counts))
for k := range counts {
keys = append(keys, k)
}
sort.Slice(keys, func(i, j int) bool {
if counts[keys[i]] != counts[keys[j]] {
return counts[keys[i]] > counts[keys[j]]
}
return keys[i] < keys[j]
})
fmt.Printf("total words: %d\n", total)
fmt.Println("top words:")
for i, k := range keys {
if i == 5 {
break
}
fmt.Printf(" %s: %d\n", k, counts[k])
}
}
Run and verify
go run main.go words.txt
Run the test command to check the implementation: go test ./....
Expected Output
For a file where the word go appears three times and others fewer, the report begins with the total:
total words: 42
top words:
go: 3
the: 2
a: 2
run: 1
test: 1
Limitations
Splits on non-letter runes, so it treats digits and apostrophes as separators and lowercases everything, which merges tokens that differ only by case.