go-02-word-frequency
1.000
Proposed solution
```go
package challenge
import (
"regexp"
"strings"
"unicode"
)
func WordFrequency(text string) map[string]int {
result := make(map[string]int)
if strings.TrimSpace(text) == "" {
return result
}
// Split on whitespace
tokens := regexp.MustCompile(`\s+`).Split(text, -1)
for _, token := range tokens {
if token == "" {
continue
}
// Strip surrounding ASCII punctuation
stripped := stripSurroundingPunctuation(token)
// Skip empty strings after stripping
if stripped == "" {
continue
}
// Lowercase and count
lowercase := strings.ToLower(stripped)
result[lowercase]++
}
return result
}
func stripSurroundingPunctuation(s string) string {
// Find first non-punctuation character from the left
start := 0
for start < len(s) && isASCII punctuation(s[start]) {
start++
}
// If all characters are punctuation, return empty string
if start >= len(s) {
return ""
}
// Find last non-punctuation character from the right
end := len(s) - 1
for end >= 0 && isASCII punctuation(s[end]) {
end--
}
return s[start : end+1]
}
func isASCII punctuation(b byte) bool {
// Check if it's ASCII punctuation (not letter or digit)
if b < 32 || b > 126 {
return true
}
// Check if it's a letter or digit
if unicode.IsLetter(rune(b)) || unicode.IsDigit(rune(b)) {
return false
}
// Check if it's punctuation (using Go's unicode.IsPunct + additional characters)
if unicode.IsPunct(rune(b)) {
return true
}
// Additional ASCII punctuation characters that are not covered by IsPunct
switch b {
case '+', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~':
return true
default:
return false
}
}
```
Wait, I see an issue with my implementation. Let me correct it:
```go
package challenge
import (
"regexp"
"strings"
"unicode"
)
func WordFrequency(text string) map[string]int {
result := make(map[string]int)
if strings.TrimSpace(text) == "" {
return result
}
// Split on whitespace
tokens := regexp.MustCompile(`\s+`).Split(text, -1)
for _, token := range tokens {
if token == "" {
continue
}
// Strip surrounding ASCII punctuation
stripped := stripSurroundingPunctuation(token)
// Skip empty strings after stripping
if stripped == "" {
continue
}
// Lowercase and count
lowercase := strings.ToLower(stripped)
result[lowercase]++
}
return result
}
func stripSurroundingPunctuation(s string) string {
// Find first non-punctuation character from the left
start := 0
for start < len(s) && isASCIIPunctuation(s[start]) {
start++
}
// If all characters are punctuation, return empty string
if start >= len(s) {
return ""
}
// Find last non-punctuation character from the right
end := len(s) - 1
for end >= 0 && isASCIIPunctuation(s[end]) {
end--
}
return s[start : end+1]
}
func isASCIIPunctuation(b byte) bool {
// Check if it's ASCII punctuation (not letter or digit)
if b < 32 || b > 126 {
return true
}
// Check if it's a letter or digit
if unicode.IsLetter(rune(b)) || unicode.IsDigit(rune(b)) {
return false
}
// Check if it's punctuation using Go's unicode.IsPunct
if unicode.IsPunct(rune(b)) {
return true
}
// Additional ASCII punctuation characters that are not covered by IsPunct
switch b {
case '+', '<', '=', '>', '?', '@', '[', '\\', ']', '^', '_', '`', '{', '|', '}', '~':
return true
default:
return false
}
}
```Test output (stdout)
ped","Elapsed":0}
{"Time":"2026-06-30T06:25:33.685640421+02:00","Action":"run","Package":"challenge","Test":"TestWordFrequency/digits_are_words"}
{"Time":"2026-06-30T06:25:33.685641991+02:00","Action":"output","Package":"challenge","Test":"TestWordFrequency/digits_are_words","Output":"=== RUN TestWordFrequency/digits_are_words\n"}
{"Time":"2026-06-30T06:25:33.685644401+02:00","Action":"output","Package":"challenge","Test":"TestWordFrequency/digits_are_words","Output":"--- PASS: TestWordFrequency/digits_are_words (0.00s)\n"}
{"Time":"2026-06-30T06:25:33.685646591+02:00","Action":"pass","Package":"challenge","Test":"TestWordFrequency/digits_are_words","Elapsed":0}
{"Time":"2026-06-30T06:25:33.685648371+02:00","Action":"run","Package":"challenge","Test":"TestWordFrequency/token_that_is_only_punctuation_is_skipped"}
{"Time":"2026-06-30T06:25:33.685650261+02:00","Action":"output","Package":"challenge","Test":"TestWordFrequency/token_that_is_only_punctuation_is_skipped","Output":"=== RUN TestWordFrequency/token_that_is_only_punctuation_is_skipped\n"}
{"Time":"2026-06-30T06:25:33.685652651+02:00","Action":"output","Package":"challenge","Test":"TestWordFrequency/token_that_is_only_punctuation_is_skipped","Output":"--- PASS: TestWordFrequency/token_that_is_only_punctuation_is_skipped (0.00s)\n"}
{"Time":"2026-06-30T06:25:33.685654741+02:00","Action":"pass","Package":"challenge","Test":"TestWordFrequency/token_that_is_only_punctuation_is_skipped","Elapsed":0}
{"Time":"2026-06-30T06:25:33.685656831+02:00","Action":"run","Package":"challenge","Test":"TestWordFrequency/empty_input"}
{"Time":"2026-06-30T06:25:33.685658671+02:00","Action":"output","Package":"challenge","Test":"TestWordFrequency/empty_input","Output":"=== RUN TestWordFrequency/empty_input\n"}
{"Time":"2026-06-30T06:25:33.685660801+02:00","Action":"output","Package":"challenge","Test":"TestWordFrequency/empty_input","Output":"--- PASS: TestWordFrequency/empty_input (0.00s)\n"}
{"Time":"2026-06-30T06:25:33.685662841+02:00","Action":"pass","Package":"challenge","Test":"TestWordFrequency/empty_input","Elapsed":0}
{"Time":"2026-06-30T06:25:33.685665491+02:00","Action":"run","Package":"challenge","Test":"TestWordFrequency/whitespace_only"}
{"Time":"2026-06-30T06:25:33.685667261+02:00","Action":"output","Package":"challenge","Test":"TestWordFrequency/whitespace_only","Output":"=== RUN TestWordFrequency/whitespace_only\n"}
{"Time":"2026-06-30T06:25:33.685669631+02:00","Action":"output","Package":"challenge","Test":"TestWordFrequency/whitespace_only","Output":"--- PASS: TestWordFrequency/whitespace_only (0.00s)\n"}
{"Time":"2026-06-30T06:25:33.685671981+02:00","Action":"pass","Package":"challenge","Test":"TestWordFrequency/whitespace_only","Elapsed":0}
{"Time":"2026-06-30T06:25:33.685674281+02:00","Action":"output","Package":"challenge","Test":"TestWordFrequency","Output":"--- PASS: TestWordFrequency (0.00s)\n"}
{"Time":"2026-06-30T06:25:33.685676611+02:00","Action":"pass","Package":"challenge","Test":"TestWordFrequency","Elapsed":0}
{"Time":"2026-06-30T06:25:33.685678391+02:00","Action":"run","Package":"challenge","Test":"TestWordFrequencyEmptyIsNonNil"}
{"Time":"2026-06-30T06:25:33.685680001+02:00","Action":"output","Package":"challenge","Test":"TestWordFrequencyEmptyIsNonNil","Output":"=== RUN TestWordFrequencyEmptyIsNonNil\n"}
{"Time":"2026-06-30T06:25:33.685682191+02:00","Action":"output","Package":"challenge","Test":"TestWordFrequencyEmptyIsNonNil","Output":"--- PASS: TestWordFrequencyEmptyIsNonNil (0.00s)\n"}
{"Time":"2026-06-30T06:25:33.685684341+02:00","Action":"pass","Package":"challenge","Test":"TestWordFrequencyEmptyIsNonNil","Elapsed":0}
{"Time":"2026-06-30T06:25:33.685686171+02:00","Action":"output","Package":"challenge","Output":"PASS\n"}
{"Time":"2026-06-30T06:25:33.685785432+02:00","Action":"output","Package":"challenge","Output":"ok \tchallenge\t0.001s\n"}
{"Time":"2026-06-30T06:25:33.685799132+02:00","Action":"pass","Package":"challenge","Elapsed":0.001}
System prompt
You are an expert programmer. Solve the task exactly as specified. Output your solution as fenced code blocks using the required file name(s) and the exact function/type signatures requested. Prefer correctness; do not include prose outside code unless asked.