需求
前两天在一个孩子英语学习的家长 QQ 群里,有家长问道《夏洛的网》的单词量是多少,有的家长用 Excel 分析出了结果,但又有人问如何按各种要求排序,这个群里没有 Excel 高手,所以我写了这个单词分析的小程序,主要是为 golang 学习练手。下面是程序的功能需求:
- 读取给定文本文件中的单词
- 分析文本文件中单词的出现频率
- 按照出现频率从高到低排序
- 出现频率相同的单词又按照首字母排序
实现
实现过程中遇到很多排序的算法问题,本人写程序经验欠缺,想到的实现方式可能很不优雅,也希望大神们给予指正。
源码
package main
import (
"bufio"
"fmt"
"io"
"os"
"regexp"
"sort"
"strconv"
"strings"
)
func main() {
file, err := os.Open("CharlotteWeb.txt")
if err != nil {
fmt.Fprintf(os.Stderr, "打开文件报错:%s\n", err)
}
charlotteWeb := make([]string, 0, 40000)
// 匹配英文单词的正则
r, _ := regexp.Compile("([\\w]+(\\'|\\-)*[\\w]+)|([\\w]+)")
bufferReader := bufio.NewReader(file)
for {
// 以换行符位单位读取文件内容
next, err := bufferReader.ReadString('\n')
if err != nil {
// 判断是否为文件尾部
if err != io.EOF {
fmt.Fprintf(os.Stderr, "读取报错:%s\n", err)
}
break
}
// 匹配英文单词
line := r.FindAllString(next, -1)
if len(line) != 0 {
// 全部转换为小写
for i, v := range line {
line[i] = strings.ToLower(v)
}
charlotteWeb = append(charlotteWeb, line...)
}
}
fmt.Println("统计结果:")
fmt.Printf("\n")
fmt.Println("夏洛的网单词总数:", len(charlotteWeb))
// 按照首写字母排序,位后面去重做准备
sort.Strings(charlotteWeb)
fmt.Printf("\n")
// 去重
ret := removeDuplicatesAndEmpty(charlotteWeb)
fmt.Println("去重后单词总数:", len(ret))
// 词频统计,并写入文件
frequencyStatistics(charlotteWeb, ret)
}
// 利用对比相邻单词是否一样的原理来去重
func removeDuplicatesAndEmpty(a []string) (ret []string) {
a_len := len(a)
for i := 0; i < a_len; i++ {
if (i > 1 && a[i-1] == a[i]) || len(a[i]) == 0 {
continue
}
ret = append(ret, a[i])
}
return
}
// 词频统计函数,并把结果写入文件
// charlotteWeb: 夏洛的网所有单词切片
// ret 夏洛的网单词去重后的切片
func frequencyStatistics(charlotteWeb, ret []string) {
// 新建词频统计写入文件
wsFile, err := os.OpenFile("word_statistics.txt", os.O_CREATE|os.O_APPEND|os.O_RDWR, 0660)
if err != nil {
fmt.Fprintf(os.Stderr, "统计文件打开错误:", err)
}
defer wsFile.Close()
// 存放去重后每个单词的出现频率
sortString := make([]int, 0, 4000)
// 存放 map[单词]出现频率
mapF := make(map[string]int, 4000)
// 对于每个单词计算出现频率,然后存入map
for _, rv := range ret {
k := 0
for _, cv := range charlotteWeb {
if rv == cv {
k++
}
}
sortString = append(sortString, k)
mapF[rv] = k
//bufW.WriteString(rv + " = " + strconv.Itoa(k) + "\r\n")
}
//fmt.Println(len(mapF))
//bufW.Flush()
// 对于保存词频的切片去重
retInt := make([]int, 0, 1000)
for i := len(charlotteWeb) - 1; i >= 0; i-- {
for _, v := range sortString {
if i == v {
retInt = append(retInt, i)
break
}
}
}
// 排序去重频率值
sort.Ints(retInt)
fmt.Printf("\n")
fmt.Printf("全部出现的频率:%v\n", retInt)
// 使用带缓冲的写入
bufW := bufio.NewWriter(wsFile)
// 判断map的值是否为频率值(频率值以排序,所以按排序写入),然后写入文件,
for i := len(retInt) - 1; i >= 0; i-- {
// 用于临时保存相同频率的单词
tempSort := make([]string, 0, 2000)
for k, v := range mapF {
if retInt[i] == v {
tempSort = append(tempSort, k)
}
}
// 对相同频率的单词以首写字母排序
sort.Strings(tempSort)
// 最后写入文件
for _, v := range tempSort {
bufW.WriteString(v + " = " + strconv.Itoa(retInt[i]) + "\r\n")
}
}
bufW.Flush()
}
输入结果
the = 1941
and = 1173
to = 804
a = 784
he = 559
of = 557
in = 457
i = 417
...
has = 48
how = 47
some = 47
them = 47
could = 46
heard = 46
fair = 45
egg = 43
never = 43
any = 42
come = 42
we = 42
who = 41
again = 40
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于