如何删除 CSV 中某个字段的逗号?

如何删除 CSV 中某个字段的逗号?

我正在使用名为 name 的 CSV 文件中有一个字段/列,这始终是第二个字段。

此列中的值如下:“Smith,John”“Brady,Tom”“Manning,Peyton”等

如何在不使用逗号的情况下(例如“Smith John”或“Brady Tom”)并保留所有内容不变?我尝试过使用 sed awk 但无法弄清楚。

答案1

如果字段被正确引用(如您所示),那么嵌入的逗号不应该成为问题(假设您使用支持 CSV 的解析器读取数据)。

如果您仍然认为需要删除名为 的字段中的逗号name,请使用支持 CSV 的解析器,例如csvkit或者磨坊主( mlr) 处理数据。

这是使用 Miller 的示例:

mlr --csv put '$name = gsub($name, ",", "")' file.csv

这将从 CSV 中读取数据file.csv,使用与您所发现的类似的替换函数awk来删除名为 的字段中的所有逗号name,然后输出可能修改的记录。

例子:

$ cat file.csv
age,name,note
47,"Hatter, Mad","Isn't actually ""mad"""
39,"Rabbit, White",Drinks too much tea
2,"Dormouse, The",Sleeps most of the time
$ mlr --csv put '$name = gsub($name, ",", "")' file.csv
age,name,note
47,Hatter Mad,"Isn't actually ""mad"""
39,Rabbit White,Drinks too much tea
2,Dormouse The,Sleeps most of the time

对于csvformat(来自 csvkit)和tr,以下内容将通过暂时将文档的分隔符更改为分号来删除所有逗号:

csvformat -D ';' file.csv | tr -d , | csvformat -d ';'

例子:

$ csvformat -D ';' file.csv | tr -d , | csvformat -d ';'
age,name,note
47,Hatter Mad,"Isn't actually ""mad"""
39,Rabbit White,Drinks too much tea
2,Dormouse The,Sleeps most of the time

或者,您可以使用(也来自 csvkit)通过一些 SQLcsvsql仅从字段中删除逗号:name

csvsql --query 'UPDATE file SET name = REPLACE(name, ",", "")' \
    --query 'SELECT * FROM file' file.csv

答案2

给定一个 CSV,如@Kusalananda的回答:

$ cat file.csv
age,name,note
47,"Hatter, Mad","Isn't actually ""mad"""
39,"Rabbit, White",Drinks too much tea
2,"Dormouse, The",Sleeps most of the time

我们有使用任何 awk 的简洁但脆弱的方式(如果第一个字段也被引用或第二个字段包含转义引号,则会中断):

$ awk 'BEGIN{FS=OFS="\""} {sub(/,/,"",$2)} 1' file.csv
age,name,note
47,"Hatter Mad","Isn't actually ""mad"""
39,"Rabbit White",Drinks too much tea
2,"Dormouse The",Sleeps most of the time

以及不太简洁但健壮的(适用于除换行符之外的任何字段内容,假设字段内的引号通过将每个字段加倍来转义)RFC 4180) 使用 GNU awk 的方式FPAT

$ awk 'BEGIN{FPAT="([^,]*)|(\"([^\"]|\"\")*\")"; OFS=","} {sub(/,/,"",$2)} 1' file.csv
age,name,note
47,"Hatter Mad","Isn't actually ""mad"""
39,"Rabbit White",Drinks too much tea
2,"Dormouse The",Sleeps most of the time

您需要使用哪一种取决于 CSV 的内容。

如果您引用的字段可以包含换行符,或者您有一个 CSV,上面的第一个脚本无法使用并且您无法获得 GNU awk,那么您需要一个不同的解决方案,例如参见使用 awk 高效解析 csv 的最稳健方法是什么

答案3

借用 @Kusalananda 的 CSV 示例,您可以使用带有默认 CSV 解析器的 Ruby:

$ ruby -r csv -e 'data=CSV.parse($<.read, **{:headers=>true})
data["name"]=data["name"].map{|e| e.gsub(/,/,"")}
puts data' file.csv
age,name,note
47,Hatter Mad,"Isn't actually ""mad"""
39,Rabbit White,Drinks too much tea
2,Dormouse The,Sleeps most of the time

或者,如果您想反转名称,使它们在没有逗号的情况下更合适:

$ ruby -r csv -e 'data=CSV.parse($<.read, **{:headers=>true})
data["name"]=data["name"].map{|e| e.split(/,\s*/,2).reverse.join(" ")}
puts data' file.csv
age,name,note
47,Mad Hatter,"Isn't actually ""mad"""
39,White Rabbit,Drinks too much tea
2,The Dormouse,Sleeps most of the time

答案4

使用(以前称为 Perl_6)

使用 Raku 的Text::CSV模块解析 CSV:

~$ raku -MText::CSV -e 'my @a = csv(in => $*IN, strict => True);  \
         @a.skip>>.[1] = @a.skip>>.[1].map: *.trans( "," => "");  \
         .join("\t").put for @a;'  <  file.csv

输入示例(来自@Kusalananda):

age,name,note
47,"Hatter, Mad","Isn't actually ""mad"""
39,"Rabbit, White",Drinks too much tea
2,"Dormouse, The",Sleeps most of the time

下面显示了制表符间隔的列输出以提高可读性,按照上面代码的指示(改为使用生成 CSV 文件join(","))。

示例输出 (1)

age name    note
47  Hatter Mad  Isn't actually "mad"
39  Rabbit White    Drinks too much tea
2   Dormouse The    Sleeps most of the time

如果您对列中的杂散空格有问题,可以使用.trim等。此外,OP 可能还希望反转第 2 列的内容以先读取名字,然后读取姓氏。如果是这样,那么split将该字段放在逗号上可能是最好的选择。请注意,您可以将上面的最终语句更改为csv(in => @a, out => $*OUT, sep_char => "\t"),这会生成真实的 TSV(或 CSV)文件:

~$ raku -MText::CSV -e 'my @a = csv(in => "Mad_Hatter.csv", strict => True);  \
         @a.skip>>.[1] = @a.skip>>.[1].map: *.split(", ").reverse;  \
         csv(in => @a, out => $*OUT, sep_char => "\t");'  < file.csv

样本输出 (2)

age name    note
47  "Mad Hatter"    "Isn't actually ""mad"""
39  "White Rabbit"  "Drinks too much tea"
2   "The Dormouse"  "Sleeps most of the time"

https://modules.raku.org/dist/Text::CSV:cpan:HMBRAND
https://github.com/Tux/CSV
https://raku.org

相关内容