【问题标题】:How to read a csv file into arrays and compare and replace it with entries from another csv file?如何将 csv 文件读入数组,并用另一个 csv 文件中的条目进行比较和替换?
【发布时间】:2019-06-14 12:23:11
【问题描述】:

我有两个 csv 文件 file1.csvfile2.csv
file1.csv 包含 4 列。

文件1:

Header1,Header2,Header3,Header4
aaaaaaa,bbbbbbb,ccccccc,ddddddd
eeeeeee,fffffff,ggggggg,hhhhhhh
iiiiiii,jjjjjjj,kkkkkkk,lllllll
mmmmmmm,nnnnnnn,ooooooo,ppppppp

文件2:

"Header1","Header2","Header3"
"aaaaaaa","cat","dog"
"iiiiiii","doctor","engineer"
"mmmmmmm","sky","blue"

所以我要做的是逐行读取file1.csv,将每个条目放入一个数组中,然后将该数组的第一个元素与file2.csv 的第一列进行比较,如果存在匹配项,则替换 column1 和file1.csv 的 column2 与 file2.csv 的对应列

所以我想要的输出是:

cat,dog,ccccccc,ddddddd
eeeeeee,fffffff,ggggggg,hhhhhhh
doctor,engineer,kkkkkkk,lllllll
sky,blue,ooooooo,ppppppp

当只有要替换的列时,我可以做到这一点。
这是我的代码:

awk -F'"(,")?' '
NR==FNR { r[$2] = $3; next }
{ for (n in r) gsub(n,r[n]) } IGNORECASE=1' file2.csv file1.csv>output.csv

我的最后一步是将整个数组转储到一个包含 10 列的文件中。 有什么建议可以改进或更正我的代码吗?

【问题讨论】:

  • 通过查看您的个人资料了解到,从最后几个问题中您没有选择任何答案作为正确答案,因此请您这样做(在您发布后的某个时间之后)并且当您看到足够的答案时您的帖子您可以选择其中任何一个答案作为正确答案@Anuj Kulkarni
  • @Tiw 是的,我的 file2.csv 可能有引号。我自己创建 file2.csv,而 file1.csv 是工具生成的文件。因此,在创建 file2.csv 时,我使用了引号。
  • @Tiw 是的,这是正确的。不会有逗号。我使用引号是因为 file2 可能有两个以上的空格分隔的单词(比如一个句子)。
  • @AnujKulkarni。始终建议发布靠近 Input_file(s) 的示例,请编辑您的帖子并让我们知道。
  • Anul 如果您的输入是逗号分隔的,那么空格或制表符就像任何其他字符一样,您不需要在字段周围加上引号,除非它们包含逗号或换行符。它们可以包含换行符吗?

标签: csv awk sed


【解决方案1】:

编辑:考虑到您的 Input_file2 的日期为 "ytest","test2" 等格式,如果是,请尝试关注。(感谢 Tiw 在他/她的帖子中提供此示例)

awk '
BEGIN{
  FS=OFS=","
}
FNR==NR{
  gsub(/\"/,"")
  a[tolower($1)]=$0
  next
}
a[tolower($1)]{
  print a[tolower($1)],$NF
  next
}
1' file2.csv file1.csv


请您尝试关注一下。

awk '
BEGIN{
  FS=OFS=","
}
FNR==NR{
  a[$1]=$0
  next
}
a[$1]{
  print a[$1],$NF
  next
}
1'  Input_file2  Input_file1

或者,如果您在 Input_file(s) 中有小写字母和大写字母的组合,请尝试以下操作。

awk '
BEGIN{
  FS=OFS=","
}
FNR==NR{
  a[tolower($1)]=$0
  next
}
a[tolower($1)]{
  print a[tolower($1)],$NF
  next
}
1'  Input_file2  Input_file1

【讨论】:

  • 感谢您的努力,我现在正在试验您的代码。
【解决方案2】:

在任一文件中使用任意 awk 和任意数量的字段:

$ cat tst.awk
BEGIN { FS=OFS="," }
{
    gsub(/"/,"")
    key = tolower($1)
}
NR==FNR {
    for (i=2; i<=NF; i++) {
        map[key,i] = $i
    }
    next
}
{
    for (i=2; i<=NF; i++) {
        $(i-1) = ((key,i) in map ? map[key,i] : $(i-1))
    }
    print
}

$ awk -f tst.awk file2 file1
Header2,Header3,Header3,Header4
cat,dog,ccccccc,ddddddd
eeeeeee,fffffff,ggggggg,hhhhhhh
doctor,engineer,kkkkkkk,lllllll
sky,blue,ooooooo,ppppppp

【讨论】:

  • NR==FNR 块中的代码一次将来自file2 的值存储在映射数组中的一个字段中,并且第二个块中的循环一次访问该数组中的一个字段.
【解决方案3】:

根据您的示例数据和 cmets 的描述,请尝试以下操作:
(从你自己的代码来看,你可能在字段周围有引号,所以我没有尝试回答。)

awk 'BEGIN{FS=OFS=","}
    NR==FNR{gsub(/^"|"$/,"");gsub(/","/,",");a[$1]=$2;b[$1]=$3;next}
    $1 in a{$2=b[$1];$1=a[$1];}
    1' file2.csv file1.csv

例如:

$ cat file1.csv
Header1,Header2,Header3,Header4
aaaaaaa,bbbbbbb,ccccccc,ddddddd
eeeeeee,fffffff,ggggggg,hhhhhhh
iiiiiii,jjjjjjj,kkkkkkk,lllllll
mmmmmmm,nnnnnnn,ooooooo,ppppppp

$ cat file2.csv
"Header1","Header2","Header3"
"aaaaaaa","cat","dog"
"iiiiiii","doctor","engineer"
"mmmmmmm","sky","blue"

$ awk 'BEGIN{FS=OFS=","}
NR==FNR{gsub(/^"|"$/,"");gsub(/","/,",");a[$1]=$2;b[$1]=$3;next}
$1 in a{$2=b[$1];$1=a[$1];}
1' file2.csv file1.csv
Header2,Header3,Header3,Header4
cat,dog,ccccccc,ddddddd
eeeeeee,fffffff,ggggggg,hhhhhhh
doctor,engineer,kkkkkkk,lllllll
sky,blue,ooooooo,ppppppp

另一种方式,更冗长,但我认为你最好理解(GNU awk):

awk 'BEGIN{FS=OFS=","}
    NR==FNR{for(i=1;i<=NF;i++)$i=gensub(/^"(.*)"$/,"\\1",1,$i);a[$1]=$2;b[$1]=$3;next}
    $1 in b{$2=b[$1];}
    $1 in a{$1=a[$1];}
    1' file2.csv file1.csv

这里注意一个陷阱,因为$1是关键,所以我们应该最后更改$1

不区分大小写的解决方案:

awk 'BEGIN{FS=OFS=","}
    NR==FNR{gsub(/^"|"$/,"");gsub(/","/,",");k=tolower($1);a[k]=$2;b[k]=$3;next}
    {k=tolower($1);if(a[k]){$2=b[k];$1=a[k]}}
    1' file2.csv file1.csv

为了代码简洁,添加变量k 并将"if" 移到里面。

【讨论】:

  • 谢谢你说第二种方法更容易理解。我尝试使用它并且它有效。
  • @AnujKulkarni 当然,很高兴它有帮助:)
猜你喜欢
  • 1970-01-01
  • 2012-09-26
  • 2019-06-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多