我有一个包含数千行的csv文件。
我需要替换特定列中的一些字符
â ; ---> a
& ; ---> &
é ; ---> é
我尝试使用此命令,但它无法正常工作
awk 'BEGIN{FS=OFS=";"} {for (i=3;i<=NF;i++) gsub("/\&\;/","\&",$3); gsub("/\·\;/", " ",$3); gsub("/\â\;/", "a",$3); gsub("/\é\;/", "e",$3); gsub(/\#/, " ",$3)}' file.csv
示例输入:
32602;1;"Wet & Dry 5029";2663,2662
预期产出:
32602;1;"Wet & Dry 5029";2663,2662
答案 0 :(得分:1)
那么,您想要使用awk
解析CSV文件并仅修改列的子集吗?
首先,解析CSV字段并不像在分隔符(,
上或在您的情况下;
)中拆分那么简单,因为在引用值时必须避免拆分。 awk
的{{1}}配方在excellent answer by @EdMorton中给出,如果您使用GNU awk
,最优雅的方法是使用FPAT
:
awk -v FPAT='[^;]*|"[^"]+"' -v OFS=';' '...'
(对于其他awk
和一些特殊情况,请参阅引用的答案。)
现在回到你的程序。 gsub
ERE参数的正确语法是/pattern/
或"pattern"
,但不是两者(例如"/pattern/"
)。
这意味着您必须按以下方式更换:
gsub("/\&\;/","\&",$3) --> gsub(/&/, "\\&", $3)
gsub("/\·\;/", " ",$3) --> gsub(/·/, " ", $3)
gsub("/\â\;/", "a",$3) --> gsub(/â/, "a", $3)
gsub("/\é\;/", "e",$3) --> gsub(/é/, "e", $3)
另请注意,在ERE正则表达式部分中,&
和;
不必转义,但在替换字符串&
中也是如此(\
还需要转义)。
此外,要仅修改列$3
,您不需要for
循环。但是,如果您确实要修改以$3
开头并以最后$NF
结尾的列范围,则需要在每个$i
中使用gsub
请致电,而不是$3
。
已修复,您的awk
程序如下:
awk -v FPAT='[^;]*|"[^"]+"' -v OFS=';' '{
for (i=3; i<=NF; i++) {
gsub(/&/, "\\&", $i)
gsub(/·/, " ", $i)
gsub(/â/, "a", $i)
gsub(/é/, "e", $i)
gsub(/#/, " ", $i)
}
print
}' file.csv
(最后的print
确保打印每一行。)
应用于您的示例(并转换为单行):
$ echo '32602;1;"Wet & Dry 5029";2663,2662' | awk -v FPAT='[^;]*|"[^"]+"' -v OFS=';' '{for (i=3;i<=NF;i++) {gsub(/&/,"\\&",$i); gsub(/·/," ",$i); gsub(/â/,"a",$i); gsub(/é/,"e",$i); gsub(/#/," ",$i)}; print}'
32602;1;"Wet & Dry 5029";2663,2662
在评论中进行了额外的故障排除后,您的问题的解决方案似乎不是替换某些特定列中的HTML实体,而是在完整文件中替换它们,因为您的CSV文件似乎格式不正确,因此后续处理器无法解析它(可能是由于未加引号的;
)。
您可以使用简单的sed
命令替换您指定的所有HTML实体,如:
sed -e 's/&/\&/g' -e 's/·/ /g' -e 's/â/a/g' -e 's/é/e/g' -e 's/#/ /g' file