none
リストボックスの部分一致検索 RRS feed

  • 質問

  •  

    お世話になってます。


    リストボックスに、フォルダ内全てのファイルのファイル名を表示させるプログラムを書きました。

     

    困った点は、
    リストボックスに表示されたファイル名を、
    例えば、comboBoxの項目で.txtを選択したら、リストボックスの項目で.txtを含んでいる項目を選択させたいと思っています。

     

    以下、自分なりに書いてみました。

            private void ComboBox_SelectedIndexChanged(object sender, EventArgs e)
            {
                if (ComboBox.Text == ".txt")
                {
                    // 「.txt」で始まる項目を検索しインデックスを取得する
                    int index = ListBox.FindString(".txt");

                    // 取得したインデックスの項目を選択する
                    ListBox.SelectedIndex = index;

                }
            }

     

    FindStringでは項目の最初の文字を検索するというのがわかりましたが、
    どうしても後方一致検索、または部分一致検索の方法がわかりません。


    皆様よろしくお願いします。

     

    開発環境:C#、.NET2.0、VS2005、WindowsXP pro

    2008年2月10日 12:16

回答

  • 外池と申します。

     

    ごくごく一般的に、あらゆる局面で文字列の一致の検査を行うには、正規表現(Regular Expression)という手法があって、.Net Frameworkにそのための機能が用意されていますから、調べてみてください。「Regex」をキーワードにして検索すれば見つかります。

     

    が、

     

    今回、実現させたい機能は、単にファイル名の拡張子による分類だけなのでしょうか? であれば、私なら、

     

      まず、希望の拡張子を小文字化して保管します。

      で、ListBoxに含まれているファイル名を一つずつ拾い出しつつ、

         そのファイル名もまず小文字化します。

         ファイル名の最後が、小文字化した拡張子と一致するか検査します。String型のEndsWith関数

                  一致すれば表示するリストに加えます。

      ListBoxに含まれるファイル名全てにこれを繰り返します。

     

    こんな感じにしますが・・・。

     

    要するに、ListBoxのメソッドを使うのではなく、ListBoxのファイル名を総当たりするところは自分で書いて、ファイル名の中の特定の文字列を探すところで、String型のメソッドを使う、ということです。

     

    2008年2月10日 12:33
  • ListBox 自体は前方一致もしくは完全一致の検索しかメソッドを提供していません。それ以外のことがしたいなら、自分で Items をループでまわして一つずつ確認していく必要があります。

    2008年2月10日 12:37
  • そういう意味では、以下のコードが一番堅いです。いくらでも応用が利きますので。Listを使う必然性が無くなりましたが(^^;

    なんか混乱させてしまったようで申し訳ありません。

     

    Code Snippet

     

     int len = ComboBox.Text.Length;

     string key = ComboBox.Text;

     string str;

     

     for (int i = 0; i < ListBox.Items.Count; i++)

     {

       str = ListBox.Items[i].ToString();

     

       if (str.Substring(str.Length - len, len) == key)

                 ListBox.SetSelected(i, true);

     }

     

     

    2008年2月11日 5:50
    モデレータ

すべての返信

  • 外池と申します。

     

    ごくごく一般的に、あらゆる局面で文字列の一致の検査を行うには、正規表現(Regular Expression)という手法があって、.Net Frameworkにそのための機能が用意されていますから、調べてみてください。「Regex」をキーワードにして検索すれば見つかります。

     

    が、

     

    今回、実現させたい機能は、単にファイル名の拡張子による分類だけなのでしょうか? であれば、私なら、

     

      まず、希望の拡張子を小文字化して保管します。

      で、ListBoxに含まれているファイル名を一つずつ拾い出しつつ、

         そのファイル名もまず小文字化します。

         ファイル名の最後が、小文字化した拡張子と一致するか検査します。String型のEndsWith関数

                  一致すれば表示するリストに加えます。

      ListBoxに含まれるファイル名全てにこれを繰り返します。

     

    こんな感じにしますが・・・。

     

    要するに、ListBoxのメソッドを使うのではなく、ListBoxのファイル名を総当たりするところは自分で書いて、ファイル名の中の特定の文字列を探すところで、String型のメソッドを使う、ということです。

     

    2008年2月10日 12:33
  • ListBox 自体は前方一致もしくは完全一致の検索しかメソッドを提供していません。それ以外のことがしたいなら、自分で Items をループでまわして一つずつ確認していく必要があります。

    2008年2月10日 12:37
  •  たかし さんからの引用

    FindStringでは項目の最初の文字を検索するというのがわかりましたが、
    どうしても後方一致検索、または部分一致検索の方法がわかりません。


    発想を変えて、ファイル名をList<string>に保存し、それをListBoxにバインドさせます。
    検索はList<string>のFindIndexで行い、見つかったインデックスをListBoxのSelectedIndexにセットすればうまく行くでしょう。

    2008年2月10日 13:39
    モデレータ
  • 皆様レスありがとうございます。

     

    trapemiya様の、

    ファイル名をList<string>に保存し、それをListBoxにバインドさせます。

    というのは具体的にはどのようにすればよろしいでしょうか?

     

    現在は、下記のようにしております。

                //FolderBrowserDialogクラスのインスタンスを作成
                FolderBrowserDialog fbd = new FolderBrowserDialog();

                //ダイアログを表示する
                if (fbd.ShowDialog(this) == DialogResult.OK)
                {
                    ListBox.Items.Clear();
                    string[] pathes = Directory.GetFiles(
                        fbd.SelectedPath, "*", System.IO.SearchOption.AllDirectories);

                    foreach (string path in pathes)
                    {
                        //ListBoxに結果を表示する
                        ListBox.Items.Add(System.IO.Path.GetFileName(path));
                    }
                }
     

    2008年2月10日 13:54
  • 以下のような感じです。

     

    List<string> list = new List<string>();

     

    foreach (string path in pathes)
    {
       list.Add(System.IO.Path.GetFileName(path));
    }

     

    ListBox.DataSource = list;

     

    検索は、

     

    ListBox.SelectedIndex = ((List<string>)ListBox.DataSource).FindIndex(delegate(string str) { return str.Contains(ComboBox.Text); });

     

    #listが見えるなら(スコープ内なら)、以下でもOK。

    ListBox.SelectedIndex = list.FindIndex(delegate(string str) { return str.Contains(ComboBox.Text); });

     

    #コードは実際に検証していませんので、微妙に違っているところは修正願います。

     

    2008年2月10日 14:20
    モデレータ
  • コードまで書いていただき、ありがとうございます。

     

            private void ComboBox_SelectedIndexChanged(object sender, EventArgs e)
            {
                if (ComboBox.Text == ".zip")
                {
                        ListBox.SelectedIndex =
                        ((List<string>)ListBox.DataSource).FindIndex(delegate(string str) { return str.Contains(ComboBox.Text); });
                }


    検索の箇所を上記のようにしました。

    しかし、リストボックスに表示される一番最初の項目しか選択されません。

     

    何度もお聞きして申し訳ございません。

    2008年2月10日 15:14
  • おかしいですね・・・。 以下のテストコードではうまく動いています。ちょっとしたことだと思うのですが、デバッグで追いかけてみてください。

     

            List<string> list = new List<string>();

     

            private void cbtn_addList_Click(object sender, EventArgs e)

            {

                list.Add("aaa.abc");

                list.Add("bbb.def");

                list.Add("ccc.ghi");

     

                this.listBox1.DataSource = list;

            }

     

            private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)

            {

                listBox1.SelectedIndex = list.FindIndex(delegate(string str) { return str.Contains(this.comboBox1.Text); });

            }

     
    #一応、誤解のないようにですが、ListBoxのItemをループで探し出す方法でも良いですよ。
    2008年2月10日 16:29
    モデレータ
  • デバックして追ってみましたが、
    ComboBoxの値が「.txt」のとき、リストボックスに表示される項目の「.txt」を含んだ最初の項目しか選択されず、
    それ以下の「.txt」を含んだ項目は選択されませんでした。
    リストボックスに表示される全ての「.txt」を含んだ項目を選択させたいのですが、以下のコードでは誤っていますでしょうか?

            List<string> list = new List<string>();

            private void OpenMenuItem_Click(object sender, EventArgs e)
            {
                //FolderBrowserDialogクラスのインスタンスを作成
                FolderBrowserDialog fbd = new FolderBrowserDialog();

                //ダイアログを表示する
                if (fbd.ShowDialog(this) == DialogResult.OK)
                {
                    string[] pathes = Directory.GetFiles(
                        fbd.SelectedPath, "*", System.IO.SearchOption.AllDirectories);

                    foreach (string path in pathes)
                    {
                        list.Add(System.IO.Path.GetFileName(path));
                    }
                    this.ListBox.DataSource = list;
                }
            }

            private void ComboBox_SelectedIndexChanged(object sender, EventArgs e)
            {
                for (int i = 0; i < ListBox.Items.Count; i++)
                {
                    int index = list.FindIndex(delegate(string str) { return str.Contains(this.ComboBox.Text); });
                    ListBox.SelectedIndex = index;
                }
            }

    何度もお聞きし申し訳ございません。
    2008年2月11日 5:00
  • そういう意味では、以下のコードが一番堅いです。いくらでも応用が利きますので。Listを使う必然性が無くなりましたが(^^;

    なんか混乱させてしまったようで申し訳ありません。

     

    Code Snippet

     

     int len = ComboBox.Text.Length;

     string key = ComboBox.Text;

     string str;

     

     for (int i = 0; i < ListBox.Items.Count; i++)

     {

       str = ListBox.Items[i].ToString();

     

       if (str.Substring(str.Length - len, len) == key)

                 ListBox.SetSelected(i, true);

     }

     

     

    2008年2月11日 5:50
    モデレータ
  • こんにちは。中川俊輔 です。

     

    外池さん、Hongliang さん、大変参考になる回答ありがとうございます。

    trapemiyaさん、サンプルコード付きの大変参考になる回答ありがとうございます。

     

    たかしさん、フォーラムのご利用ありがとうございます。

    その後いかがでしょうか?

    勝手ながら問題解決に有用そうな回答に回答済みチェックをつけさせていただきました。

    追加の質問等あればぜひ投稿してください!

     

    問題解決につながる回答があった場合は、なるべく回答済みボタンを押してチェックを付けてください。

    たかしさんはチェックを解除することもできますので、ご確認ください。

     

    それでは!

    2008年2月18日 8:10