- 今天的golang学习被txt中的回车符困扰了半个小时, 最后才傻傻的发现, mark一下
问题描述
我想从两个文件 test1.txt
和test2.txt
中分别按行读取字符串, 然后统计字符串的出现次数.
两文件内容分别如下, 是我手动键入的:
test1
test2
test2
test1
- 按照逻辑来说, 最终统计结果是,
test1
和test2
都分别出现两次, - 但是结果却并不如我所想, map中有四个字符串, 打印出来是
test1
test1
test2
test2
明明它们都一样, 怎么统计的呀, 难道是golang的map有问题???
- 遇事先想自己的问题, 不能怀疑语言, 不能怀疑编译器, 这是从百度面试官那里学到的
我的代码如下
package main
import (
"fmt"
"io/ioutil"
"os"
"strings"
)
func main() {
//fmt.Println("dup3,test filename")
counts := make(map[string]int)
filenames := []string{
"data\\test1.txt","data\\test2.txt"}
for _,fileName := range filenames{
data, err := ioutil.ReadFile(fileName) // 返回字节数组, 以及错误类型
//fmt.Println(data)
if err != nil{
fmt.Fprintf(os.Stderr, "dup3: %v\n", err)
continue
}
for _,str := range strings.Split(string(data),"\n"){
counts[str]++
}
}
for line,cnt := range counts{
if cnt >1 {
fmt.Printf("%d\t%s\n",cnt,line)
}
}
}
问题分析与解决
- 为什么
test1
和test1
不同呢, 它们明明是同一个字符串 - 经过思考, 我猜到了答案, 回车符, 然后就是验证
- 原因在于, readFile是读入的字节切片, 而不是按行读入
- 我们将readFile读取到的字节切片直接打印, 可以得到如下结果
[116 101 115 116 49 13 10 116 101 115 116 50]
[116 101 115 116 50 13 10 116 101 115 116 49]
- 这是因为我在敲txt的时候, 习惯性敲了回车键, ascll码13对应的就是
\r
, 即回车, 而10对应的就是换行 - 所以原因是因为我手敲的文件内容, 其中为了换行, 用了回车符, 而换行本身又是
\n
, 所以在上面我们用/n
来进行split
会产生长度为6和长度为5的字符串, 分别是test1\r
和test1
,test2\r
和test2
, 自然又不一样了, 然后打印出来, 因为经过了系统函数的格式化, 删除了回车符, 所以看起来都一样, 于是搞不清是哪出了问题 - 这个问题只是因为我们手敲导致, 如果是代码写入txt, 那么一般都不会使用回车符+换行符, 而是直接使用换行符, 则没有本文的问题出现
- 解决方法为, 将
split
的sep
换成\r\n
即可 - 然后就能正确打印结果啦