2017-02-28 38 views
1

我有一個非常大的csv文件,該文件太大而無法在此操作的Excel中打開。使用另一個csv文件在csv文件中查找和替換多個模式

我需要更換特定字符串爲約6000記錄了在CSV的1.5mil的,字符串本身是像這樣的逗號分隔格式:

ABC,FOO.BAR,123456 

兩邊有其他列那沒有關係。我只需要足夠的數據來確保最終的數據字符串(數字)是唯一的。

我與串另一個文件替換和替換字符串等(上述):

"ABC,FOO.BAR,123456","ABC,FOO.BAR,654321" 

因此,在上述情況下123456是由654321替換一個簡單的(但令人極其慢)方法是在記事本++中打開兩個文檔,然後找到第一個字符串,然後用第二個字符串替換,但是有超過6000個記錄,這不是很好。

我希望有人可以提供腳本解決方案的建議?例如:

$file1 = base.csv 
$file2 = replace.csv 

For each row in $file2 { 
awk '{sub(/$file2($firstcolumn)/,$file2($Secondcolumn)' $file1 
} 

雖然我不是完全確定如何適應AWK做這樣的操作..

編輯:對不起,我本來應該更具體,在我更換CSV數據只有兩個列;兩個原始字符串!

+0

剩下的問題:做'ABC,FOO.BAR,123456'在_data_文件('base.csv')表示_3_場抑或是被封閉在一個'場_single_的內容「......」 _在文件_中? – mklement0

回答

2

這將是當然,如​​果你的分隔符不是領域內使用的更容易...

您可以分兩步做,從查找文件中創建一個sed腳本,並用它來進行主數據文件替代

例如, (假設有在田裏沒有逃脫引號,可能不成立)

$ awk -F'","' '{print "s/" $1 "\"/\"" $2 "/"}' lookup_file > replace.sed 
$ sed -f replace.sed data_file 
+0

這是一個完美的解決方案,但配備了一個警告:爲了使這個完全健壯,你不得不逃離同時在搜索和替換字符串元字符(在樣本輸入,只有'.'是一個問題) - 'sed'不提供_literal_字符串替換。 – mklement0

+0

字段應在數據文件中引用,否則帶逗號的字段將破壞完整性。你在'sed'中轉義所有元字符是正確的,但不確定是否需要這個文件。另一個問題是如果在字段中也有逃脫的引號。 – karakfa

+1

或避免與'的sed -f <所述tmp文件(AWK -F ' 「」' '{打印 「S /」 $ 1 「\」/ \ 「」 $ 2 「/」}' lookup_file)data_file'。 –

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中被指示通過"-F\")在輸入到字段破裂;請注意,這假定您的字符串不包含轉義嵌入式"字符。

  • 剩餘塊,然後處理該數據文件:

    • 對於每個輸入線路,它循環通過搜索字符串並尋找在當前行的匹配:

      • 找到匹配項後,將替換字符串替換爲搜索字符串,並匹配停止符。
    • print只是打印(可能修改)的行。

注意,因爲你想文字字符串替換,正則表達式基礎的功能,如sub()贊成的文字字符串處理函數index()substr()明確地避免。另外:由於您認爲數據文件兩邊都有列,因此可以考慮通過將,放置在數據文件的任一側(這可以在awk腳本中完成)來使搜索/替換字符串更加健壯。

+1

我到底去了SED解決方案,但感謝您的解決方案,並感謝甚至更多的不同部分的它的偉大解釋! – AMcNall

2

我會建議使用具有CSV解析庫,而不是試圖用shell工具來做到這一點的語言。例如,紅寶石:

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 2.1 +;用舊的Rubys代替這個:

replacements = Hash[*CSV.open('replace.csv','r').to_a.flatten] 

你只需要CSV替換文件;這是假定您可以將替代其他文件作爲純文本,從而加快了一點東西,並避免了對解析出新/舊串到字段自己。

相關問題