以下の記事は、「重複している行を探して表示する」というものです。
重複している行を1行だけ残して、削除する、というサンプルは、
VBAのお勉強 Excelで1行残して重複行を削除
こちらをご覧下さい。

このブログのリファラーを見ていたら、「Excel VBA 重複行」で検索されている方がいました。

その方はたぶん

http://www.simple-sys.com/blog/2008/03/13/43/

のページを見られたようですが、 これは2列で重複している行を探す、という形の重複行を探すものです。

ただ、一般的に「重複行を探す」といったら、

160-01.jpg

みたいなデータがあったときに、

「あ」、「う」、「お」、「く」が重複している、

っていうような探し方、のほうが多いような気がします。

なので、今回はVBAを使って、重複した行を探してみたいと思います。

160-02.jpg

こんな感じで、A列で重複しているデータにはそのB列に「重複」って文字が 入るようにしてみたいと思います。

考え方は、こんな感じ。

  • 1行目から見ていって、
    • その行の値を次の行から探していき、
      • 同じ値があったら、その行と、今見てる行のB列に「重複」の文字を入れる
    • これを最後の行まで繰り返す
  • っていう作業を最後の1つ前の行まで繰り返す

こんな感じです。

一番最後が、「最後の1つ前の行まで」ってなってます。

なんで最後の行まで繰り返さないか? その理由は簡単です。

最後の行にはもう、「次の行」がありません。

最後の行はそれ以降にチェックする対象がないので、最後の1つ前の行まで、ということになります。

ということで、コードを作っていきます。

まずは、A列を最初から最後の1つ前までイミディエイトウィンドウに表示させてみます。

Sub test()

    Dim lastgyou As Integer
    Dim i        As Integer
    
    'Sheet1を選択します
    Sheets("Sheet1").Select
    
    '最後の行を求めます
    ActiveSheet.Range("A1").End(xlDown).Select
    lastgyou = ActiveCell.Row
    
    '最後の行まで、B列を空にします。
    For i = 1 To lastgyou
        
        ActiveSheet.Cells(i, 2).Value = ""
    
    Next
    
    '1行目から最後の行の1行前まで、とりあえずイミディエイトウィンドウに表示
    For i = 1 To lastgyou - 1
        
        Debug.Print (ActiveSheet.Cells(i, 1).Value)
    
    Next

End Sub

まず、最終行の行番号を求めるのはいつもどおりです。

B列の値を全部消して、その後で、1行ずつ表示しています。

実行すると、

160-031.jpg

(^^)いつもとほぼ同じですね。

それでは、今の行より下の行をチェックしていくプログラムを追加してみます。

Sub test()
    
    Dim lastgyou As Integer
    Dim i        As Integer
    Dim j        As Integer
    Dim atai     As String
    
    'Sheet1を選択します
    Sheets("Sheet1").Select
    
    '最後の行を求めます
    ActiveSheet.Range("A1").End(xlDown).Select
    lastgyou = ActiveCell.Row
    
    '最後の行まで、B列を空にします。
    For i = 1 To lastgyou
        ActiveSheet.Cells(i, 2).Value = ""
    Next
    
    '1行目から最後の1つ前の行までチェックします
    For i = 1 To lastgyou - 1
        
        '今見ている i 行目の値を atai という変数に入れておきます。
        atai = ActiveSheet.Cells(i, 1).Value
        
        '今見ている行( i )の1つ下から、最後の行まで、チェックします
        For j = i + 1 To lastgyou
            
            'もし、ataiと j 行目が、同じ値だった場合
            If atai = ActiveSheet.Cells(j, 1).Value Then
                
                'i行目と、j行目が重複していることになるので、
                '両方の行のB列に、「重複」という文字を代入します。
                ActiveSheet.Cells(i, 2).Value = "重複"
                ActiveSheet.Cells(j, 2).Value = "重複"
            End If
        Next
    Next
End Sub

ataiという変数と j という変数を追加しました。

atai に今見ている i 行目のA列の値を入れておきます。

j で今見ている行の次の行から最後の行まで繰り返し見ていき、 j 行目の値と atai の値が一致した場合、「重複」という値をB列に代入する、となっています。 実行してみると、

160-04.jpg

ん、できました(^^)

これで完成。。。なんですが。

例えば、「あ」について見てみると、

160-05.jpg

「あ」は1行目と、8行目にあります。

1行目のチェックが終わった段階で、

160-06.jpg

こんな状態になってます。

プログラムはこの後、2行目、3行目と同じように進んでいきますが、 8行目まで来たときについて考えてみます。

8行目は「あ」です。

「あ」はすでに1行目でチェックしたときに重複していることが分かっていますので、 B列には、「重複」という文字が入っています。

ということは。。。。

8行目まで来たときですが、この「あ」については探す必要がないですよね?(^^;)

なぜなら、すでに1行目で重複していることはわかっていますし、仮に9行目以降に「あ」があったとしても、 それはすでに1行目でチェックした際に重複と判断されてB列に「重複」が入ってるはずです。

ということで、

もしB列に「重複」という文字列が入っている場合、その行の値については探す必要がない、

ということをプログラムに組み込んでみます。

Sub test()
    
    Dim lastgyou As Integer
    Dim i        As Integer
    Dim j        As Integer
    Dim atai     As String
    
    'Sheet1を選択します
    Sheets("Sheet1").Select
    
    '最後の行を求めます
    ActiveSheet.Range("A1").End(xlDown).Select
    lastgyou = ActiveCell.Row
    
    '最後の行まで、B列を空にします。
    For i = 1 To lastgyou
        ActiveSheet.Cells(i, 2).Value = ""
    Next
    
    '1行目から最後の1つ前の行までチェックします
    For i = 1 To lastgyou - 1
        
        'もし、今見ている行がまだ「重複」じゃない場合
        If ActiveSheet.Cells(i, 2).Value = "" Then
            
            '今見ている i 行目の値を atai という変数に入れておきます。
            atai = ActiveSheet.Cells(i, 1).Value
            
            '今見ている行( i )の1つ下から、最後の行まで、チェックします
            For j = i + 1 To lastgyou
                
                'もし、ataiと j 行目が、同じ値だった場合
                If atai = ActiveSheet.Cells(j, 1).Value Then
                    
                    'i行目と、j行目が重複していることになるので、
                    '両方の行のB列に、「重複」という文字を代入します。
                    ActiveSheet.Cells(i, 2).Value = "重複"
                    ActiveSheet.Cells(j, 2).Value = "重複"
                End If
            Next
        End If
    Next

End Sub

IF文を使って、i 行目のB列に「重複」が入っていない場合だけ、内側の For Nextを実行するようにしています。

実行してみると、

160-07.jpg

ん、おっけいですね(^^)

こちらにアップしておきます→vbastudy_16.xls

http://q.hatena.ne.jp/1206528619

「関数を利用した方法」ということで、やはりVBAではないですが(^^;)

まず、A列の値の中に「A」が入っている位置を調べてみます。

これは、こないだこちらで使いました、「FIND」を使えばよさそうです。

FINDワークシート関数の書式は、

=FIND(検索文字列, 対象, 開始位置)

(開始位置は省略可能、省略した場合は1となり、先頭から探す) で、

見つかった場合、その文字位置(左から何文字目か)、

見つからなかった場合、#VALUE!というエラー を返します。

B,C,D列は最終的に値を入れるので、とりあえず、E列でいろいろやってみます。

E1の計算式に、

   =FIND("A",A1)

と入れて、E4までオートフィルしてみます。
143-01.jpg
ん、おっけい(^^)。

というか、全部一文字目に入っているから、「1」になりますね(^^;)

もし、A列に「A」が入っていなかった場合、

例えば、A5に「BC」という値を入れて、E5にも先ほどの計算式をオートフィルしてみます。

143-02.jpg

ん、入ってなければ「#VALUE!」でエラーです(^^)

んでは、こんどは「B」を探してみます。F列を使います。

Bが入っていない場合の値も入れておきます。A6に「AC」と入れときます。

F列の式はさっきとほとんど同じですね。F1に

   =FIND("B",A1)

と入れ、F6までオートフィルします。すると、こんな感じ。

143-03.jpg

ん。後はこの値を使ってA列から文字列を抜き出せばよさそうです。

文字列を抜き出すには、MIDワークシート関数を使います。書式は、

=MID(対象文字列,抜き出す開始文字位置,抜き出す文字数)

となります。 抜き出す開始文字位置はAが見つかった位置の次、でよいですから、(E列の値+1)、でよいですね。

抜き出す文字数は、、、これはちょっとめんどくさいですね(^^;)

「Bが見つかった位置の前まで」、つまり、(F列の値-1)文字目、まで抜き出せばよいですが、

MID関数で必要になるのは、「抜き出す文字数」です。

これは具体的なデータで考えたほうがわかりやすいですね。 2行目で考えるのがよさそうです。

A2の値、「A10B5C」で、E列の値が「1」、F列の値は「4」です。 この文字列でAとBの間を抜き出すには、

=MID(A2,2,2)

となります。A2の値を2文字目から、2文字分抜き出す。ということです。

2つ目のパラメータの「2」は、これは「A」という文字が見つかった1文字目の次で、1+1=2、これは分かりやすいですね。

3つ目のパラメータの「2」、これはどうやって求めればよいでしょうか?

143-04.jpg

上の図で黄色と水色の間に何文字あるか?ということですね。

これは、(水色の文字位置)-(黄色の文字位置)-1 という式で間の文字数が求められます。

上の例ですと、4-1-1=2、です。

これは黄色と水色がどこの位置にあってもこの計算式で大丈夫です。

ということで。MIDの関数をB1に入れてみます。

   =MID(A1,E1+1,F1-E1-1)

E列が「A」が見つかった位置、F列が「B」が見つかった位置、ですので、 上記のような式になります。

この式をB6までオートフィルすると、

143-05.jpg

ん、エラーが出ている行は、AまたはBが入っていないのでエラーですが、 それ以外の行は問題なさげです(^^)。

AとBがくっついている場合、(1行目、3行目、4行目)、3つめのパラメータは0になります。

0の場合、MID関数は空の文字列になるようですね。

あとはエラーを表示しないようにします。

E列とF列いずれかがエラーだったら何も表示しない、でなければ表示するという感じにしてみます。

B1に、

   =IF(OR(ISERROR(E1),ISERROR(F1)),"",MID(A1,E1+1,F1-E1-1))

と入れ、B6までオートフィルします。

143-06.jpg

ん、いいんでないかい?(^^) OR関数は初めて使ったかな?

=OR(式1,式2)

が書式で、式1もしくは式2のいずれかがTRUEならば、この式自体がTRUEになり、 そうでなければ(式1も式2もFALSEの場合)FALSEになる、という関数です。

E列、F列どっちかがエラーならば何も表示せず、そうでなければ表示する、って感じですね。

ん、B列はこれでいいかな?

んでは、次、C列。 これは考え方はB列と全く同じですね。

A列の値の文字列の中で「C」がある位置を探します。G列に入れときます。 G1に、

   =FIND("C",A1)

と入れ、G6までオートフィル。 C1に、

   =IF(OR(ISERROR(F1),ISERROR(G1)),"",MID(A1,F1+1,G1-F1-1))

と入れ、C6までオートフィル。

 143-07.jpg

ん、よいですね(^^) 最後、D列。これは今までの2つとはちょっと違いますね。

「C」以降の文字列を抜き出す、って事ですが、、、

   =MID(A1,G1+1,

ここまではすぐわかりますが、、、3つ目のパラメータをどうしましょうかね?

143-081.jpg

例えば、上の例だと6文字目から1文字抜き出す、 下の例では、4文字目から3文字抜き出す、 っていうのはわかりますけど、この何文字抜き出すのかをどうやって求めるか?

これは、A1の全体の文字数が必要になります。

(全体の文字数)-(Cが見つかった位置) の式で、抜き出す文字数が求められます。

上の例ですと、6-5=1 下の例ですと、6-3=3 となりますね。

全体の文字数が変わったとしても、

143-09.jpg

上の例では、9-5=4 下の例では4-3=1 という感じで抜き出す文字数が導き出せます。

ということでA列の文字数を求める必要があります。 文字数を求める関数は、LENです。書式は、

=LEN(文字列)

で、これで文字列の長さを求めることが出来ます。

では、D列の計算式を作ってみます。 まず、エラーとか気にしないで作ってみます。D1に

   =MID(A1,G1+1,LEN(A1)-G1)

といれ、D6までオートフィルします。

143-10.jpg

ん、いい感じ(^^)

ただ、これはA列に「C」が入っていない場合のことを考えていません。

例えば、A7に「AB」という値を入れて、D1の計算式をD7までオートフィルすると、

143-11.jpg

当然こうなります。ので、これもエラーが出ないようにします。 D1に、

   =IF(ISERROR(G1),"",MID(A1,G1+1,LEN(A1)-G1))

と入れます。 もしG列がエラーだったら何も表示せず、そうでなければ表示する。という感じですね。

D7までオートフィルします。

143-12.jpg

ん、エラーが消えました(^^)

一応これで、質問者さんが必要としている値を求めることは出来ました。

ただ、、、E列以降、邪魔ですよね?(^^;)

分かりやすくするために「A」の文字位置などを代入してきましたが、 ワークエリアを使うと見苦しいので、使わないようにしたいです。

B1の計算式は、今、

   =IF(OR(ISERROR(E1),ISERROR(F1)),"",MID(A1,E1+1,F1-E1-1))

ですが、このうち、E1とF1の部分、ここを、E1とF1の計算式に置き換えてしまえば、 E1とF1は必要なくなります。

 143-13.jpg

E1となっているところに、FIND(“A”,A1) F1となっているところに、FIND(“B”,A1)を入れればよいですね。

入れ替えた式が、こちら。

   =IF(OR(ISERROR(FIND("A",A1)),ISERROR(FIND("B",A1))),"",MID(A1,FIND("A",A1)+1,FIND("B",A1)-FIND("A",A1)-1))

・・・(^^;)こうなってしまうと、もうこの式が何を表しているのか、パッと見ではわからないですね。

ただ、この式にはもうE1、F1は入っていませんので、E1、F1の計算式を消しても、B1の値は求まります。

同じようにC1の計算式は、

   =IF(OR(ISERROR(FIND("B",A1)),ISERROR(FIND("C",A1))),"",MID(A1,FIND("B",A1)+1,FIND("C",A1)-FIND("B",A1)-1))

D1の計算式は、

   =IF(ISERROR(FIND("C",A1)),"",MID(A1,FIND("C",A1)+1,LEN(A1)-FIND("C",A1)))

となります。 これでE列以降はもういらないので、消してみます。

143-14.jpg

ん、E列以降がなくても、抜き出せてますね(^^)

一応完成かな?ここに置いておきます→vbastudy_15.xls

ただし・・・(^^;) この状態でも、まだ問題があります。

A列にAやB、Cが複数入っていた場合は想定していません。

この場合は、 最初に出てきたA、最初に出てきたB、最初に出てきたCで判断しますので、2文字目以降は無視する形になります。

また、例えばA列に「COBRA」というように、A、B、Cが想定している順番で入っていない場合などにも、 エラーになってしまいます。

もし、この場合でも、「A」と「B」の間は「R」という形で抜き出すのであれば、Aの位置とBの位置を調べて、 どちらが先に現れるかによって、計算式を分ける必要があります。。。。

今回はめんどくさいのでそこまではやりません(^^;)

© 2011 simple blog いろいろ勉強中 Suffusion theme by Sayontan Sinha