• ベストアンサー

重複した文字列をカウントして取り出したい

初めて質問させていただきます。 VB初心者です。 ソートされた文字列の書き込まれたファイルを読み、 (文字列は、 ”000” ”001” ”001” ”001” ”002” ”002” ”003” といったように書き込まれています。) そこから、3つ連続して並んでいる文字列を探し出して、 その文字列と、3つ連続していた文字列がいくつあったのか表示するプログラムを作りたいのですが、 どうにも処理速度が遅く、さらに行数が1万を超えると、応答なしになってしまいます。 どなたか、上手い処理の方法があれば、ぜひともご教授の程をお願いします。 Public Class Form1 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click OpenFileDialog1.FileName = "" OpenFileDialog1.InitialDirectory = "c:\" If OpenFileDialog1.ShowDialog() = Windows.Forms.DialogResult.OK Then TextBox1.Text = My.Computer.FileSystem.ReadAllText _ (OpenFileDialog1.FileName, System.Text.Encoding.Default) End If End Sub Private Sub TextBox1_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged End Sub Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click Dim x As Integer Dim xyz As Integer '行数を調べる。 Dim i As Integer = TextBox1.Lines.Length TextBox2.Text = (i - 1 & "行") MessageBox.Show("一時停止") For ix = 0 To i - 2 '1行目と2行目を比較 If TextBox1.Lines(x) = TextBox1.Lines(x + 1) Then '2行目と3行目を比較 If TextBox1.Lines(x + 1) = TextBox1.Lines(x + 2) Then '3つある番号を記入。 TextBox2.Text = TextBox2.Text + vbCrLf + TextBox1.Lines(x + 2) '3回重複したことをカウント。 'MessageBox.Show("3発見") xyz = xyz + 1 Else End If Else End If '調べる行を+1 x = x + 1 Next TextBox2.Text = TextBox2.Text + vbCrLf + ("3つ以上は、" & xyz & "個") End Sub Private Sub OpenFileDialog1_FileOk(ByVal sender As System.Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles OpenFileDialog1.FileOk End Sub Private Sub TextBox2_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox2.TextChanged End Sub End Class

質問者が選んだベストアンサー

  • ベストアンサー
  • redfox63
  • ベストアンサー率71% (1325/1856)
回答No.1

文字列の連結を TextBox2.Text = TextBox2.Text + vbCrlf + TextBox1.Lines(x + 2) といった具合に直接コントロールプロパティで行っているので 速度の低下を招いているのでしょう ループの外で Dim sb as New System.Text.StringBuilder と宣言しておいて条件に合致した場合 sb.AppendLine( TextBox1.Lines( n ) ) xyz += 1 としてメモリー上で文字の連結をします ループが終了したら sb.AppendLine( String.Format( "3つ以上は、{0}個", sb.Length ) ) TextBox2.Text = sb.ToString() といった具合にして見ましょう 重複チェック中の『応答無し』の対処としてはループ中の適当なタイミングでApplication.DoEventsを実行してみましょう ループの中で if x mod 100 = 0 then   Application.DoEvents() end if といった具合に 100回ごとに実行するとか また条件チェックを if TextBox1.Lines(x) = TextBox1.Lines(x+1) AndAlso _   TextBox1.Lines(x) = TextBox1.Lines(x+2) then といった具合に 1つのif文で判定するとか 2つの条件を Andで連結すると毎回両方の条件をチェックします AndAlsoで連結すると 前者『TextBox1.Lines(x) = TextBox1.Lines(x+1)』が不成立なら後者の条件はチェックしません 進行状況を可視化するために ProgressBarなどを使ったり Labelなどに現在のチェックライン番号(または残数)を表示してみましょう

maimai_san
質問者

お礼

ありがとうございます。さっそく試してみます。

maimai_san
質問者

補足

無事に解決しました。ありがとうございました。

その他の回答 (1)

  • hotosys
  • ベストアンサー率67% (97/143)
回答No.2

textboxの.Linesで調べているのが原因だと思います。 文字列配列に取り込んで計算すれば、速くなると思います。 それと質問のプログラムでは3個以上を調べているはずなのに、4個以上に対処していないように見えます。 それと、1データのチェックに3データを調べるのは効率が悪いと思います。 と言う訳で以下のようなのはどうでしょうか? Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click Dim xyz As Integer '配列に取得 Dim d() As String = Split(TextBox1.Text, vbCrLf) '配列の最大引数取得 Dim ub As Integer = UBound(d) '元文字列の最後が改行の時にできる余計なデータ分を減らす If d(ub) = "" Then ub = ub - 1 '行数を調べる。 Dim lines As Integer = ub + 1 TextBox2.Text = (lines & "行") MessageBox.Show("一時停止") '最初のデータは1個目 Dim n As Integer = 1 '2番目のデータから最後まで調べる For i = 1 To ub If d(i) = d(i - 1) Then '前のデータと同じならn+1個目 n = n + 1 Else '違うなら1個目 n = 1 End If If n = 3 Then '3つ目なら番号を記入。 TextBox2.Text = TextBox2.Text + vbCrLf + d(i) xyz = xyz + 1 End If Next TextBox2.Text = TextBox2.Text + vbCrLf + ("3つ以上は、" & xyz & "個") End Sub p.s. どうしてもlines()で取得する場合は、文字列に取り込んでTextBox1.Lines(x)でアクセスする回数を減らす方がいいと思います。

maimai_san
質問者

お礼

ありがとうございます。 こちらの方法も、ぜひ試させていただきます。

関連するQ&A