Text-Processing

查找和替換重複項

  • March 23, 2018

我有一個包含串聯電子郵件的文件,如下所示:

id  emails
1   jeff@email.com
2   larry@email.com
3   jprice@email.com,jeff@email.com,jeff@stacko.com

每行只有不同的電子郵件,但從一行到另一行可能存在重複,如上面第 1 行和第 3 行所示。我需要從文件中刪除重複項,以便文件如下所示:

id  emails
1   jeff@email.com
2   larry@email.com
3   jprice@email.com,jeff@stacko.com

這意味著我需要檢查每一行與它後面的所有行。鑑於我擁有的數據量,這對於任何類型的迭代腳本都是不可行的。我覺得有一種簡單(或至少可行)的方法可以使用awksed完成此任務,但我還沒有找到任何方法。

如果您的文件是如下所示的真實 csv 文件(simple-csv),則可以使用以下awk命令:

輸入:

jeff@email.com
larry@email.com
jprice@email.com,jeff@email.com,jeff@stacko.com

命令:

awk -F, '{ COMMA="";i=0; while (++i<=NF) {
          $1=$i; printf (!seen[$1]++)?COMMA$i:""; COMMA=","}; print ""
}' infile.csv

輸出:

jeff@email.com
larry@email.com
jprice@email.com,jeff@stacko.com

如果沒有,並且輸入就像在您的問題中給出的一樣,您可以使用以下代替:

awk  'NR==1; NR>1{id=$1"\t"; COMMA=$1="";split($0, ar, /,| /); 
   for(i in ar){if(ar[i]!=""){printf(!seen[ar[i]]++)?id""COMMA""ar[i]:""; COMMA=",";id=""}
} print ""}' infile

輸出:

id  emails
1       jeff@email.com
2       larry@email.com
3       jprice@email.com,jeff@stacko.com

這是一個 sed 解決方案,它適用於您的確切輸入格式,並且希望也能快速執行。

sed -rz 's:[ \t]+:,:g;s:$:,:mg;:l;s:,([^,]+),(.*),\1,:,\1,\2,:;tl;s:,$::mg;s:^([^,]+),:\1\t:mg' file.csv

這個怎麼運作:

‘-z’ 標誌載入整個文件,因此以下程式碼只應用一次,而不是預設情況下在每一行上應用。

#transform input format to actual CSV format
s:[ \t]+:,:g;s:$:,:mg;
#loop while the s command can still find and replace
:l;
   #main code: find two identical cell values anywhere and delete the latter
   #on a very big file this can suffer from backtracking nightmare
   s:,([^,]+),(.*),\1,:,\1,\2,:;
tl;
#transform format back
s:,$::mg;s:^([^,]+),:\1\t:mg

引用自:https://unix.stackexchange.com/questions/432698