我一直在寻找这个问题的答案,并且已经接近,但还不够接近。我们收到一个 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
,则将它们替换为空字符串。指示打印包含所有修改(如果有)的行1
。awk
如果需要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