使用 SED 从 CSV 文件中删除不属于另一个单词的整个单词

使用 SED 从 CSV 文件中删除不属于另一个单词的整个单词

我一直在寻找这个问题的答案,并且已经接近,但还不够接近。我们收到一个 CSV 文件,其中包含文本“NULL”,无需替换任何内容。例子:

  • 输入
    12345,George,MCNULLMAN,NULL,green,NULL
    
  • 更换应导致:
    12345,George,MCNULLMAN,,green,
    

我尝试将此作为测试,但显然单词边界不考虑逗号。

echo "MCNULLMAN,HELLO,NULL,NULL" | sed 's|bNULL/b||g'

使用sed 's|NULL||g'一段时间效果很好,直到我们收到NULL中间包含一个人的名字。有什么建议么?

答案1

当使用表格数据时,我建议使用awk

awk 'BEGIN{FS=OFS=","}{for (i=1;i<=NF;i++) if ($i=="NULL") $i=""}1' input.csv

这会将输入和输出字段分隔符设置为,。然后它会迭代该行的所有字段,如果它们完全等于NULL,则将它们替换为空字符串。指示打印包含所有修改(如果有)的行1awk

如果需要sed,我建议对字段分隔符进行硬编码(同时允许前面的逗号作为行首,尾随逗号作为行尾):

sed -E 's/(^|,)(NULL)(,|$)/\1\3/g' input.csv 

这利用捕获组来记录前面和后面字段分隔符的实际值(可能是逗号或行首/行尾,具体取决于修改的字段),并替换整个“前面的” -separator+field+trailing-separator”仅由“preceding-separator+trailing-separator”组合。

请注意这仅适用于“简单 CSV”文件,保证不会NULL被引用。

答案2

使用磨坊主( mlr) 清空NULL无标头 CSV 输入文件中的确切字符串的每个字段:

$ cat file.csv
12345,George,MCNULLMAN,NULL,green,NULL
$ mlr --csv -N put 'for (k,v in $*) { v == "NULL" { $[k] = "" } }' file.csv
12345,George,MCNULLMAN,,green,

这也适用于包含复杂引用的 CSV 文件:

$ cat file.csv
12345,"George
NULL,MacGregor",MCNULLMAN,"NULL,NULL","NULL",green,"""NULL"""
$ mlr --csv -N put 'for (k,v in $*) { v == "NULL" { $[k] = "" } }' file.csv
12345,"George
NULL,MacGregor",MCNULLMAN,"NULL,NULL",,green,"""NULL"""

在上面的示例记录中,只有一个字段NULL仅包含字符串,即第四个字段(之前green)。它还包含一组不必要的引号。 (最后一个字段是"NULL",包括文字引号,因此不会被清空。NULL第二行的第一个字段是第一个字段的一部分,其中包含文字换行符。同样,NULL,NULL不会触及值为 的字段。)

答案3

使用awk

awk '{sub(/^NULL,/, ",");
gsub(/,NULL,/, ",,"); 
sub(/,NULL$/, ",")}1' file

使用csvsql

file.csv 作为简单的 CSV 文件。

12345,George,MCNULLMAN,NULL,green,NULL
$ csvsql -H -I --query 'select * from file' file.csv | csvformat -K 1
12345,George,MCNULLMAN,,green,

带有复杂引用的 file.csv。

12345,"George
NULL,MacGregor",MCNULLMAN,"NULL,NULL","NULL",green,"""NULL"""
$ csvsql -H -I --query 'select * from file' file.csv | csvformat -K 1
12345,"George
NULL,MacGregor",MCNULLMAN,"NULL,NULL",,green,"""NULL"""
  • -H为了--no-header-row

  • -I为了--no-inference。如果没有此选项,命令将更12345改为12345.0.

  • -K n为了--skip-lines。首先跳过n线。

使用此命令是因为csvsql -H命令添加了标题行。- K 1删除它。

答案4

使用(以前称为 Perl_6)

~$ raku -ne '.split(",").map(*.subst: :global, /^NULL$/ ).join(",").put;'  file

或者

~$ raku -ne '.split(",")>>.subst( :global, /^NULL$/ ).join(",").put;'  file

上面是用 Raku(Perl 编程语言家族的成员)编写的答案。使用非自动打印逐行标志逐行读取文件-ne。这些标志指示 Raku 运行每行标志后面的代码。

输入数据(即行)加载到 Raku 的$_主题变量中。从这里开始,文本$_.split以逗号开头(注意上面:您可以删除前导$_并只写.split)。

接下来,对所得元素进行map遍历,以subst对每个元素应用一个方法。这里,/^NULL$/与以 开始和结束NULL且中间没有其他内容的元素的每个匹配都被替换为空(:global副词/参数是多余的,但在其他情况下可能有用)。

最后,修改后的元素join以逗号和 out 组合在一起put

输入示例:

12345,George,MCNULLMAN,NULL,green,NULL
12345,George,MCNULLMAN,NULL,green,nail
NULL,George,MCNULLMAN,NULL,green,neal

示例输出:

12345,George,MCNULLMAN,,green,
12345,George,MCNULLMAN,,green,nail
,George,MCNULLMAN,,green,neal

https://raku.org

相关内容