返回每列包含数字的行数

返回每列包含数字的行数

我尝试过使用此问题的答案,但无法适应我的具体需求。

https://stackoverflow.com/questions/58005013/count-the-number-of-rows-per-column-in-bash-shell

我的目标是编写一个 bash 脚本来读取 csv 文件,并返回每列的计数。计数是包含数值(包括短划线、句点和冒号)的行数。

给定一个像这样的 csv 文件:

2012-01-01 12:01:01, 1,3.2,NA,9,P
2012-01-01 12:01:01, 1,3,5,9,P
2012-01-01 12:01:01, 1,Bad,5,9,P
2012-01-01 12:01:01, 1,3,5,9,P
2012-01-01 12:01:01, 1,3,NA,9.7,P

我期望我的结果是:

5,5,4,3,5,0

答案1

使用awk

awk -F, -v OFS=, '
   { gsub(/[:. -]/, ""); for(c=1; c<=NF; c++) if($c==$c+0) count[c]++ }
END{ for(i=1; i<c; i++) printf "%d%s", count[i], (i+1<c?OFS:ORS) }' infnile

输出:

5,5,4,3,5,0

答案2

有多种方法可以做到这一点。

perl -sF, -lane 'my $i;
  $s[$i++] += /^\h*\d/ for @F;
  }{print @s;
' -- -,=, yourfile.csv

GNU sed + rs + awk + ​​粘贴实用程序:

sed -E '
  s/(^|,)[0-9][^,]*/\11/g
  s/(^|,)[^0-9,]*/\10/g
' yourfile.csv |
rs -Tc,  |
awk '{print gsub(/1/,"")}'|
paste -sd, -

awk -F, -v OFS=, '
{
  for (i=1; i<=NF; i++)
    s[i] += $i ~ /^ *[0-9]/
}
END {
  for (i=1; i in s; i++)
    printf "%s%s", s[i], \
      (i+1 in s) ? OFS : ORS
}' yourfile.csv

答案3

您可以使用正则表达式测试每个逗号分隔的字段(例如,查看它是否包含十进制数字)。将其转换为元素指标并进行运行计数。

例如使用 perl:

$ perl -F, -MList::MoreUtils=pairwise -lne '
  BEGIN{@c = ()}
  @ind = map { scalar $_ =~ /\d/ } @F; @c = pairwise { $a + $b } @c, @ind
  }{
  print join ",", @c
' file
5,5,4,3,5,0

类似的方法在 awk 中应该很简单 - 您只需要显式地循环元素即可。

答案4

使用(以前称为 Perl_6)

raku -e 'my $a; for [Z] lines.map(*.subst(" ", :global).split(",")) { 
      $a.push: m:g/ [\d+ % <[-:.]>]+ /.elems }; say $a.join(",");'       

输入示例:

2012-01-01 12:01:01, 1,3.2,NA,9,P
2012-01-01 12:01:01, 1,3,5,9,P
2012-01-01 12:01:01, 1,Bad,5,9,P
2012-01-01 12:01:01, 1,3,5,9,P
2012-01-01 12:01:01, 1,3,NA,9.7,P

示例输出:

5,5,4,3,5,0

上面是用 Raku(Perl 编程语言家族的成员)编写的答案。首先$a声明一个标量。然后简单地lines读入并处理内部空白,只需通过map-ping 输入并使用删除空白subst(什么都不替换)即可。然后每个元素(行)都在逗号split,,从而将行分成列。

完成第一个lines.map(*.subst(" ", :global).split(","))操作后,列和行与 Raku 的“zip”运算符交换[Z],该运算符连续拉出表示列表的元素(例如构成表的第一列的所有元素),并将它们组合起来,直到元素位于一个列表中的位置已耗尽。

然后,针对正则表达式测试每个列元素,该正则表达式寻求与由包含, or , or的自定义字符类\d分隔(使用 Raku 的%修饰量词)的数字匹配。每个列匹配都被布尔化为with ,并对元素求和,然后-ed 到标量上。最后返回结果。-:.True.soelemspush$asay

两个注意问题:

  1. 除了我所展示的(TMTOWTDI)之外,当然还有另一种方法来处理内部空白,例如,使用 Raku 的:s“sigspace”正则表达式副词。

  2. 可以使用较短的代码和/或不保存到 Raku 变量来处理输入文本。下面的示例代码(但是,按行返回计数):

raku -e 'for [Z] lines.map(*.subst(" ", :global).split(",")) { 
      say m:g/ [\d+ \% <[-:.]>]+ /.elems };'   

示例输出:

5
5
4
3
5
0

https://docs.raku.org/language/regexes#Modified_quantifier:_%,_%%
https://raku.org

相关内容