如果值不在列表中,则从 CSV 中删除值

如果值不在列表中,则从 CSV 中删除值

我有一个 CSV 表,其中包含 100 行和数列的数字。我有另一个列表,它是一个 1 列的文件,其中包含表中的一些数字。有没有办法可以从 CSV 中删除列表中没有的所有值?

我以为我可以用于grep -f列表文件,但我很挣扎,因为我想要删除的一些值与我想要保留的值位于同一行。

例如

CSV 表:

11,12,13 
11,10,12,13 

列表文件:

13
11

输出:

11,,13 
11,,,,13 

或者替代地

11,13 
11,13 

答案1

以下awk程序假设您的 CSV 字段不包含前导或尾随空格:

awk 'BEGIN {FS=OFS=","}
     NR==FNR{valid[$1];next}
     {for (i=1;i<=NF;i++) {if (!($i in valid)) {$i=""}}} 1' validvalues.txt input.csv 

它将首先处理validvalues.txt包含有效值的文件,然后处理实际的 CSV 文件。

  • BEGIN部分中,输入和输出的字段分隔符设置为,
  • 在处理第一个文件时(由 表示NR,全局行计数器,等于FNR,每个文件行计数器),我们只需将允许的值记录为数组 中的索引valid,否则跳过处理到下一个输入行。
  • 处理第二个文件时,我们迭代所有字段并检查字段内容是否是 的“数组索引”的一部分valid。如果没有,我们将字段值设置为空字段。
  • 看似杂乱的1打印当前行,包括迄今为止所做的所有修改。

关键点是($i in valid)测试是基于字符串的比较,因此如果“有效值”文件中的列条目或 CSV 文件中的字段包含前导/尾随空格,则比较将要求相同的空格也在其中相应的其他文件,这可能会导致意外的行为。

正如@glenn jackman 提到的该程序可以简化如下:

awk 'BEGIN {FS=OFS=","}
     NR==FNR{valid[$1]=$1;next}
     {for (i=1;i<=NF;i++) {$i=valid[$i]}} 1' validvalues.txt input.csv 

在这里,我们实际上也将有效值注册为“数组值”。这个想法是,由于无效值在 中没有条目validvalid[$i]因此将自动计算为空字符串,而对于有效值,它将返回值本身。

但请注意,性能会稍慢,因为它不必要地替换“字段值本身”,并且如果“有效值”文件很大,则需要更多内存,这可能会成为问题。

答案2

如果您有用于多字符 RS 和 RT 的 GNU awk:

$ awk -v RS='[,\n]' 'NR==FNR{a[$0]; next} {ORS=RT} $0 in a' list file.csv
11,13
11,13

答案3

您可以创建一个列表,用不需要的值的管道分隔

list=$(<list.txt tr '\n' '|')

你将会拥有13|11|

然后运行一个磨坊主搜索和替换

mlr --nidx --fs "," -S put 'for (k in $*) {if($[k]!=~"^('"$list"')$"){$[k] = gsub($[k], $[k], "")}}' input.csv

具有

11,,13
11,,,13

相关内容