CSVファイルを読み込んで、キーが重複したレコードだけを出力するスクリプトです。
重複レコードだけを出力するには、1件前のレコードと同一のキーを持つレコードがあれば、1件前のレコードを出力すると同時に、1件前のレコードのキーと異なる場合でも、さらにもう1件前(つまり2件前)のキーを保存しておき、1件前のキーと2件前のキーが同じ場合も1件前のレコードを出力するようにしています。こうすることによって、重複レコードをすべて出力できるのです。
実際に応用する場合は、入出力データのファイル名などを変更してください。また、入力データはキー順に並べ替えてあることが前提となっています。Rubyを利用して並べ替えを行う場合については、[2-4.ソート(並べ替え)処理]を参照してください。
なお、同様の処理を行う[3-2-5.ハッシュを使って、キーの重複したデータだけを出力する]については、入力データをキー順に並べ替えておく必要はありません。
# double.rb
# 内容 : 重複チェックプログラム(重複データのみ出力する)
# 前提 : 重複チェックしたいキーであらかじめソートしておく。
# Copyright (c) 2002-2015 Mitsuo Minagawa, All rights reserved.
# (minagawa@fb3.so-net.ne.jp)
# 使用方法 : c:\>ruby double.rb
#
# 入力ファイル
in1_file = open("double.txt","r")
# 出力ファイル
out1_file = open("double_only.txt","w")
# 初期値設定
in1_key = nil #入力キー
sv_key = nil #1件前の保存キー
sv_key2 = nil #2件前の保存キー
in1_ctr = 0 #入力件数
save1 = [] #保存データ
# 主処理
while (line1 = in1_file.gets)
line1.chomp!
in1_ctr += 1
in1 = (line1 + ',')
.scan(/"([^"\\]*(?:\\.[^"\\]*)*)",|([^,]*),/)
.collect{|x,y| y || x.gsub(/(.)/, '\1')}
#キー項目が単独のとき
in1_key = in1[0]
#キー項目が複数のとき
#1番目と2番目と3番目の項目がキーとなる場合
# in1_key = in1[0] + in1[1] + in1[2]
if (sv_key == in1_key)
out1_file.print save1.join(","),"\n"
sv_key2 = sv_key
elsif ((sv_key2 == sv_key) &&
(sv_key != nil))
out1_file.print save1.join(","),"\n"
out1_file.print "-" * 80,"\n"
end
sv_key = in1_key
save1 = in1
end
if ((in1_ctr > 0) &&
(sv_key2 == sv_key))
out1_file.print save1.join(","),"\n"
end
# ファイルのクローズ
in1_file.close
out1_file.close
スクリプトではまず「$sv_key」に1件前のキーを保存しておき、「$sv_key2」に2件前のキーを保存しておきます。そして、入力キーと1件前のキーを比較して同じ(したがって重複している)場合に、出力しています。また、入力キーと1件前のキーとを比較して異なっている場合でも、さらに1件前のキーである「$sv_key」と、2件前のキーである「$sv_key2」が同じである場合(したがって重複している)には出力しています。これは重複したキーを持つレコードの最後のレコード(重複したキーを持つレコードが3件あれば、3件目のレコード)を出力するためのロジックです。
その他注意すべきこと
その他、注意すべき点は入力データがタブ区切りなどの場合とキーが複数ある場合の処理です。
1.入力データがタブ区切りの場合
上記のスクリプトはCSV2形式以外の引用符(")を使用する場合を含め、あらゆるCSVファイルに対応できるようになっていますが、入力データがタブ区切りの場合は
line1.chomp!
in1 = (line1 + ',')
.scan(/"([^"\\]*(?:\\.[^"\\]*)*)",|([^,]*),/)
.collect{|x,y| y || x.gsub(/(.)/, '\1')}
となっている箇所を
in1 = line1.split("\t",-1);
と変更します。
2.キーが複数の項目から成り立っている場合
「in1_key = in1[0]」の部分を
in1_key = in1[0] + in1[1] + in1[2]
のように変更します(文字列の連結は「+」を使う)。
aaa,1 aaa,2 aaa,3 bbb,1 ccc,1 ccc,2 ddd,1 ddd,2 ddd,3 ddd,4 eee,1 fff,1 ggg,1 hhh,1 hhh,2 hhh,3
aaa,1 aaa,2 aaa,3 -------------------------------------------------------------------------------- ccc,1 ccc,2 -------------------------------------------------------------------------------- ddd,1 ddd,2 ddd,3 ddd,4 -------------------------------------------------------------------------------- hhh,1 hhh,2 hhh,3