【问题标题】:How to replace multiple characters with AWK in a specific column of a csv file?如何在 csv 文件的特定列中用 AWK 替换多个字符?
【发布时间】:2020-04-18 01:18:33
【问题描述】:

我有一个包含数千行的 csv 文件。

我需要替换特定列中的一些字符

&acirc ; ---> a
&amp ; ---> &
&eacute ; ---> é

我试过这个命令,但它不起作用

awk 'BEGIN{FS=OFS=";"} {for (i=3;i<=NF;i++) gsub("/\&amp\;/","\&",$3); gsub("/\&middot\;/", " ",$3); gsub("/\&acirc\;/", "a",$3); gsub("/\&eacute\;/", "e",$3); gsub(/\#/, " ",$3)}' file.csv

示例输入:

32602;1;"Wet &amp; Dry 5029";2663,2662

预期输出:

32602;1;"Wet & Dry 5029";2663,2662

【问题讨论】:

  • 从您的file.csv发布几行输入
  • 欢迎堆栈溢出,请在代码标签中发布示例输入和预期输出(根据论坛规则)。

标签: csv awk


【解决方案1】:

那么,您想用awk 解析一个CSV 文件并只修改一部分列?

首先,解析 CSV 字段并不像在分隔符上拆分(,,或者在您的情况下为 ;)那么简单,因为在引用值时必须避免拆分。 awk 的配方在 excellent answer by @EdMorton 中给出,如果您使用 GNU awk,最优雅的方法是使用 FPAT

awk -v FPAT='[^;]*|"[^"]+"' -v OFS=';' '...'

(对于其他awks和一​​些特殊情况,请参阅引用的答案。)

现在回到你的程序。 gsub ERE 参数的正确语法是 /pattern/"pattern",但不能同时使用两者(例如 "/pattern/")。

这意味着您必须按如下方式替换:

gsub("/\&amp\;/","\&",$3)     -->  gsub(/&amp;/, "\\&", $3)
gsub("/\&middot\;/", " ",$3)  -->  gsub(/&middot;/, " ", $3)
gsub("/\&acirc\;/", "a",$3)   -->  gsub(/&acirc;/, "a", $3)
gsub("/\&eacute\;/", "e",$3)  -->  gsub(/&eacute;/, "e", $3)

另请注意,在 ERE 正则表达式部分,&amp;; 不必转义,但在替换字符串 &amp; 中需要转义(\ 也需要转义)。

此外,如果只修改$3 列,则不需要for 循环。但是,如果您真的想修改以$3 开头并以最后一个$NF 结尾的列范围,则需要在每个gsub 调用中使用$i,而不是$3

已修复,您的 awk 程序如下所示:

awk -v FPAT='[^;]*|"[^"]+"' -v OFS=';' '{
    for (i=3; i<=NF; i++) {
        gsub(/&amp;/, "\\&", $i)
        gsub(/&middot;/, " ", $i)
        gsub(/&acirc;/, "a", $i)
        gsub(/&eacute;/, "e", $i)
        gsub(/#/, " ", $i)
    }
    print
 }' file.csv

(末尾的print 确保打印每一行。)

应用于您的示例(并转换为单行):

$ echo '32602;1;"Wet &amp; Dry 5029";2663,2662' | awk -v FPAT='[^;]*|"[^"]+"' -v OFS=';' '{for (i=3;i<=NF;i++) {gsub(/&amp;/,"\\&",$i); gsub(/&middot;/," ",$i); gsub(/&acirc;/,"a",$i); gsub(/&eacute;/,"e",$i); gsub(/#/," ",$i)}; print}'
32602;1;"Wet & Dry 5029";2663,2662

在 cmets 中进行其他故障排除后,您的问题的解决方案似乎不是替换某些特定列中的那些 HTML 实体,而是在完整文件中替换它们,因为您的 CSV 文件似乎格式不正确,因此后续处理器无法解析它(可能是由于未引用 ;s)。

您可以使用简单的sed 命令替换您指定的所有 HTML 实体,例如:

sed -e 's/&amp;/\&/g' -e 's/&middot;/ /g' -e 's/&acirc;/a/g' -e 's/&eacute;/e/g' -e 's/#/ /g' file

【讨论】:

  • 感谢您的回答,但还不行。这是我的 csv 文件的示例行 --- > 32602;1;"Wet & Dry 5029";2663,2662 当我申请 csv 文件时,我仍然有 &它没有在 & 中被替换。知道为什么吗?
  • 现在看看,问题是在; 上拆分,所以你真的需要一个正确的 CSV 解析。
  • 感谢您提供非常清晰的信息。但实际上,还是有问题的。 csv 编码不好,这就是为什么我想替换这些包含特殊字符“;”的字符和带有 awk 的“#”,因为当我将 csv 导入数据库时​​会引发问题。当我应用新代码时,我现在在第 3 列的许多行中添加了“;”而不是空格。
  • 在这种情况下,我是否可以建议您尝试使用简单的sed -e 's/&amp;amp;/\&amp;/g' -e 's/&amp;middot;/ /g' -e 's/&amp;acirc;/a/g' -e 's/&amp;eacute;/e/g' -e 's/#/ /g' file &gt; newfile 而不是awk?无论它们在文件中的什么位置,它都会替换这些序列,但它似乎对你有用。
  • 在我的答案中添加了最终解决方案。
猜你喜欢
  • 2021-07-24
  • 2017-05-20
  • 1970-01-01
  • 2017-03-13
  • 2014-03-05
  • 2014-03-27
  • 2015-08-15
  • 2021-09-12
  • 1970-01-01
相关资源
最近更新 更多