我有一个非常大的csv文件太大而无法在excel中打开此操作。
我需要在csv的1.5mil中替换大约6000条记录的特定字符串,字符串本身采用逗号分隔格式,如下所示:
ABC,FOO.BAR,123456
任何一方的其他列都无关紧要。我只需要足够的数据来确保最终的数据字符串(数字)是唯一的。
我有另一个文件,其中包含要替换的字符串和替换字符串(如上所述):
"ABC,FOO.BAR,123456","ABC,FOO.BAR,654321"
所以在上面的情况下,123456正在被654321取代。一个简单(但令人发狂的慢)方法是在notepad ++中打开两个文档并找到第一个字符串然后用第二个字符串替换,但是有超过6000个记录这个不是很好。
我希望有人能就脚本解决方案提出建议吗? e.g:
$file1 = base.csv
$file2 = replace.csv
For each row in $file2 {
awk '{sub(/$file2($firstcolumn)/,$file2($Secondcolumn)' $file1
}
虽然我不完全确定如何使awk适应这样的操作..
编辑:对不起,我应该更具体一点,我替换csv中的数据只有两列;两个原始字符串!
答案 0 :(得分:3)
awk -F\" '
NR==FNR { subst[$2]=$4; next }
{
for (s in subst) {
pos = index($0, s)
if (pos) {
$0 = substr($0, 1, pos-1) subst[s] substr($0, pos + length(s))
break
}
}
print
}
' "$file2" "$file1" # > "$file1.$$.tmp" && mv "$file1.$$.tmp" "$file1"
#
之后的部分显示了如何用输出替换输入数据文件。
与NR==FNR
关联的块仅针对第一个输入文件执行,该文件具有搜索和替换字符串。
subst[$2]=$4
构建一个关联数组(字典):键是搜索字符串,值是替换字符串。
字段$2
和$4
分别是搜索字符串和替换字符串,因为已指示Awk通过"
({{1}将输入分成字段}});请注意,这假设您的字符串不包含转义的嵌入式 -F\"
字符。
然后剩余的块处理数据文件:
对于每个输入行,它遍历搜索字符串并在当前行上查找匹配项:
"
只打印(可能已修改)的行。
请注意,由于您需要 literal 字符串替换,因此明确避免使用基于 regex 的函数,例如print
,以支持文字字符串处理函数{{ 1}}和sub()
。
顺便说一句:既然你说数据文件的两边都有列,那么考虑通过在index()
的任意一侧放置substr()
来使搜索/替换字符串更加健壮(这可以在{ {1}}脚本)。
答案 1 :(得分:2)
如果您的分隔符未在字段中使用,那么当然会更容易...
您可以分两步完成,从查找文件创建一个sed
脚本,并将其用于替换主数据文件
(假设字段中没有转义引号,可能不会保留)
$ awk -F'","' '{print "s/" $1 "\"/\"" $2 "/"}' lookup_file > replace.sed
$ sed -f replace.sed data_file
答案 2 :(得分:2)
我建议使用带有CSV解析库的语言,而不是尝试使用shell工具执行此操作。例如,Ruby:
require 'csv'
replacements = CSV.open('replace.csv','r').to_h
File.open('base.csv', 'r').each_line do |line|
replacements.each do |old, new|
line.gsub!(old) { new }
end
puts line
end
请注意Enumerable#to_h
需要Ruby v2.1 +;用旧版Rubys代替:
replacements = Hash[*CSV.open('replace.csv','r').to_a.flatten]
您只需要CSV替换文件;这假设您可以将替换文件作为纯文本应用于另一个文件,这会加快速度并避免将旧/新字符串解析为字段本身。