计算简化的csv文件中所有数据字段的最大字符长度并输出到txt

计算简化的csv文件中所有数据字段的最大字符长度并输出到txt

给定一个包含许多数据字段 (>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逐行非自动打印命令行标志:

  1. 数组在BEGIN块中声明,
  2. 要删除标题行(第一个答案),++$请使用匿名计数器 ( ) 来跳过第一行。或者(第二个答案),once next可以使用,
  3. split在块/循环的主体内,每一行都以逗号读入,并且每个结果元素都被输入以获得(字符)map的数量。chars这些被推入@a数组,
  4. 读入所有行后,该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

相关内容