![计算简化的csv文件中所有数据字段的最大字符长度并输出到txt](https://linux22.com/image/55853/%E8%AE%A1%E7%AE%97%E7%AE%80%E5%8C%96%E7%9A%84csv%E6%96%87%E4%BB%B6%E4%B8%AD%E6%89%80%E6%9C%89%E6%95%B0%E6%8D%AE%E5%AD%97%E6%AE%B5%E7%9A%84%E6%9C%80%E5%A4%A7%E5%AD%97%E7%AC%A6%E9%95%BF%E5%BA%A6%E5%B9%B6%E8%BE%93%E5%87%BA%E5%88%B0txt.png)
给定一个包含许多数据字段 (>50) 的简化 CSV(每行最多一行),如何计算每个数据字段的最大字符长度,然后将所有计数导出到 txt 文件?顺便说一句,我想忽略包含列标题的文件的第一行。
例如,给定输入
These,are,the,column_headings_which_may_be_very_long_but_they_don't_count
abcdefghij,abcdefghijk,abcdefghijkl,abc
aardvark,bat,cat,dog
ant,bee,cow,abcdefghijklm
最终结果可能类似于以下内容,其中第一列表示原始文件中的数据字段,第二列表示字段的最大长度:
1 | 10
2 | 11
3 | 12
4 | 13
即,第 1 列中最长值的长度为 10 ( abcdefghij
),第 2 列中最长值的长度为 11 ( abcdefghijk
),依此类推。
我在该网站上进行了一些研究,发现了几种方法,可以在指定特定数据字段时以相当简单的方式计算最大长度。例如,使用 cut 和 wc 命令来计算文件中第二个字段的最大长度:
cut -d, -f2 test.csv | wc -L
但是我怎样才能获取命令并将其循环到所有数据字段然后输出呢?
答案1
如果我正确理解你的问题,这将满足你的要求:
awk -F, 'NR!=1 { if (max_NF < NF) max_NF = NF;
for (i=1; i<=NF; i++) if (max[i] < length($i)) max[i] = length($i) }
END { for (i=1; i<=max_NF; i++) printf "%-2d | %d\n", i, max[i] }'
答案2
我没有看到示例文件的链接,但您可以使用awk
命令来执行此操作。
如果您可以指定您可能拥有的分隔符以及您需要计算的确切字段。
awk '{ FS = "," } ; { if(NR!=1) gsub(/"/, "", $2) ; print NR "|" length($2) } ' test.csv
您可以将此输出重定向到您想要的任何文件。
答案3
使用米勒 ( mlr
)计算每个字段值的最大长度。输入被读取为 CSV,输出生成为“xtab”文件(每个文件一个键+值对):
$ mlr --c2x stats1 -a maxlen --fr . file
These_maxlen 10
are_maxlen 11
the_maxlen 12
column_headings_which_may_be_very_long_but_they_don't_count_maxlen 13
--fr .
该操作的参数是stats1
计算名称与正则表达式匹配的所有字段.
(即每个已命名的字段)的最大长度。
正如您所看到的,米勒保留了字段名称并_maxlen
为每个字段添加了后缀。
要读取 CSV 文件,就好像它的第一行是一条记录而不是标题,然后删除该第一行并执行相同的最大值计算:
$ mlr --c2x -N filter -x 'NR == 1' then stats1 -a maxlen --fr . file
1_maxlen 10
2_maxlen 11
3_maxlen 12
4_maxlen 13
通过附加rename
操作,我们可以_maxlen
从所有字段的名称中删除后缀:
$ mlr --c2x -N filter -x 'NR == 1' then stats1 -a maxlen --fr . then rename -r '(.*)_maxlen$,\1' file
1 10
2 11
3 12
4 13
答案4
使用乐(以前称为 Perl_6)
~$ raku -ne 'BEGIN my @a;
unless ++$ == 1 {
@a.push: $_.split(",").map: *.chars;
};
END say( ++$ ~ " | " ~ $_ ) for ([Z] @a).map: *.max;' file
或者:
~$ raku -ne 'BEGIN my @a;
once next;
@a.push: $_.split(",").map: *.chars;
END say( ++$ ~ " | " ~ $_ ) for ([Z] @a).map: *.max;' file
这是用 Raku(Perl 编程语言家族的成员)编写的答案。 Raku 具有对 Unicode 的高级支持,因此字符计数是准确的。
我们首先使用(awk
类似)-ne
逐行非自动打印命令行标志:
- 数组在
BEGIN
块中声明, - 要删除标题行(第一个答案),
++$
请使用匿名计数器 ( ) 来跳过第一行。或者(第二个答案),once next
可以使用, split
在块/循环的主体内,每一行都以逗号读入,并且每个结果元素都被输入以获得(字符)map
的数量。chars
这些被推入@a
数组,- 读入所有行后,该
END
块就会执行。数组@a
经过[Z]
转换,使得行和列互换。一旦发生这种情况,我们就可以map
进入每个数组位置的元素,并获得max
.最后输出数据,使用++$
匿名计数器提供行号(字符串连接是通过~
波形符完成的)。
输入示例:
These,are,the,column_headings_which_may_be_very_long_but_they_don't_count
abcdefghij,abcdefghijk,abcdefghijkl,abc
aardvark,bat,cat,dog
ant,bee,cow,abcdefghijklm
示例输出:
1 | 10
2 | 11
3 | 12
4 | 13
注意:没有对每行的列数进行错误检查:[Z]
转换将简单地将数量过多的行截断为公共行(即示例中的 4 列)。请参阅下面的第一个链接,以在 Raku 中完成此任务,无论每行有多少列数。
https://unix.stackexchange.com/a/774828/227738
https://docs.raku.org/language/unicode
https://raku.org