Fork me on GitHub

Go语言开发-集合类型-例子:猜测分隔符

4.4.1.例子:猜测分隔符

有些情况下,我们可能会处理一大堆数据文件,每个文件中每个记录占用一行,但是不同的文件可能会使用不同的分隔符(例如,制表符、空格或“*”)。要批量处理这些文件,我们需要确定每个文件使用的分隔符。本节中的guess_separator例子(在文件guess_separator/guess_separator.go中)将尝试识别要处理的每个文件的分隔符。

通过如下命令运行该例子:

程序首先从给定的文件中读取前五行(如果文件行数少于5行,则读取所有行)并通过这些行来猜测所使用的分隔符。

和以前一样,我们只介绍main()函数及其调用的函数,而略过imports部分。

main()函数首先检查是否在命令行中指定了文件,如果没有,就输出帮助信息并终止程序执行。

我们创建了一个[]string切片来保存我们感兴趣的分隔符;对于空格分隔的文件,我们按照惯例认为其使用“”(空字符串)作为分隔符。

程序首先从文件中读取出前5行数据并处理,这里并没有给出readUpToNLines()函数的具体代码,因为之前我们就已经介绍过如何从文件中按行读取数据的例子。而与之前的例子不同的是,readUpToNLines()函数是读取指定的行数,如果行数不足,则读取全部并返回。

接下来我们将介绍main()函数中调用的其它函数,下面是createCounts()函数。

createCounts()函数用于填充一个矩阵,该矩阵保存的是每行中每个分隔符的数量。

该函数首先创建了一个int类型的二维切片,其长度和切片separators的一样。如果有四个分隔符,那么counts的值就会被设置为 [nilnilnilnil]。外层的循环将每个nil值替换为保存有每行中每个分隔符的数量的int[]切片,所以每个nil值被替换为[00000],而之所以如此是因为Go语言总是将类型初始化为其零值。

内层的的for循环用于计算counts。对于每一行,我们都会统计每个分隔符出现的次数并相应的更新counts。strings.Count()函数返回其第二个字符串参数在第一个字符串参数中出现的次数。

例如,给定一个制表符分隔的文件,其中一些字段中含有项目符号、空格和星号,我们可能会得到一个形如[[33333] [00430] [00000] [12200]]的counts矩阵。counts中的每个元素都是是int []类型的切片,其保存了每个分隔符(制表符、星号、竖线、项目符号)在读取的前五行出现的的次数,从当前数据来看,每行都有三个制表符,两行含有星号(一行四个,另一行三个),三行含有项目符号,所有行都不含有竖线。对于我们来说,很明显制表符是分隔符,但是对于程序来说,必须自己去判断,这里使用了guessSep()函数来做到这一点。

上面函数的作用是在counts切片中找到第一个其元素全部一样且不为零的[]int切片。

该函数首先遍历counts切片中的每一个元素(一个元素代表一个分隔符在所有行中出现的次数),并假设每个元素中的所有值都相同。函数将第一个count count设置为初始count,也就是,分隔符在第一行中出现的次数;然后遍历剩余的count值,也就是分隔符在其它行中出现的次数,如果遇到count值与前一个不一样,则内层循环结束,并继续处理下一个分隔符;如果内层循环执行完毕,但是same的值仍为true,且count值大于0,则表示我们已经找到了要找的分隔符,并立即返回它。如果最后没有找到分隔符,就返回一个空字符串,这就意味着,数据是以空格分隔的,或者完全没有被分隔。

report() 函数其实是不重要的,只是用来说明文件所用的分隔符。

本节中的例子介绍了一维切片和二维切片(separators,、lines和counts)的典型用法。在下一个例子中,我们将会介绍映射、切片及其排序。


目录


作者:Johnson
原创文章,版权所有,转载请保留原文链接。

发表评论

电子邮件地址不会被公开。 必填项已用*标注