【问题标题】:on-the-fly search algorithm in listbox列表框中的动态搜索算法
【发布时间】:2012-08-22 07:23:20
【问题描述】:

所以,我有一个包含 x 个项目的列表框。在列表框的顶部,我有一个 TextBox(这是搜索字段)。如果它不包含搜索词(代码中的变量关键字),我尝试开发一种从列表框中删除项目的算法。这应该发生在用户键入的每个键上(即时)。所以,代码:

   private void _keywordTextBox_TextChanged(object sender, EventArgs e)
    {
        string keyword = _keywordTextBox.Text;

        if (keyword == searchtext || isSpace) // do nothing if space is typed - searchtext is a templatetext in the textbox ("type here to search...")
            return; // ignore
        else if (keyword == "")
        {
            listBox.Items.Clear();

            foreach (string s in originalList)
                listBox.Items.Add(s);
        }
        else
        {
            List<string> selection = new List<string>();

            foreach (string s in originalList) // originalList is the listbox at startup
                selection.Add(s);

            listBox.BeginUpdate();
            string[] keywordSplit = keyword.Split(' ');

            try
            {
                for (int i = originalList.Count - 1; i >= 0; i--)
                {
                    string[] selectionSplit = selection[i].Split(' ');

                    int l = 0; // number of hits

                    for (int j = 0; j < selectionSplit.Length; j++)
                    {
                        for (int k = 0; k < keywordSplit.Length; k++)
                        {
                            if (selectionSplit[j].ToLower().Contains(keywordSplit[k].ToLower()))
                            {
                                l++;
                                break;
                            }
                        }
                    }

                    if (l < keywordSplit.Length) // Not hit on all keywords
                        selection.RemoveAt(i);
                }
            }
            finally
            {
                listBox.Items.Clear();

                foreach (string s in selection) // Add selection in listbox
                    listBox.Items.Add(s);

                if (listBox.Items.Count > 0)
                    listBox.SetSelected(0, true); // Select first item in listbox

                listBox.EndUpdate();
            }
        }
    }

这个问题很难描述,除了它没有按预期工作。据我所知,这种行为是零星的。

如果我搜索“ck flow”,我应该会在 stackoverflow 上获得成功。更重要的是,如果我删除字符(退格键的删除键),它也应该起作用。有人吗?

编辑:更多细节:

列表框应根据用户搜索的内容在每次击键时缩小和扩大。列表框应保留与用户键入的关键字匹配的每个项目,并过滤掉不匹配的项目。

【问题讨论】:

  • 我猜你想要实现的功能是由微软的ComboBoxAutoComplete 提供的功能看到这个stackoverflow.com/questions/6243611/…
  • 请更详细地解释代码的预期用途。应该显示或过滤哪些元素?也许再举一些例子。
  • @yogi No :) 它只搜索字符串的开头,而不是中间。

标签: c# winforms search


【解决方案1】:

或者你可以尝试制定一个正则表达式:

private void textBox1_TextChanged(object sender, EventArgs e)
{
    string keyword = textBox1.Text;
    if (string.IsNullOrEmpty(keyword.Trim()))
    {
        listBox1.Items.Clear();
        listBox1.Items.AddRange(_originalList.ToArray());
    }
    else
    {
        Regex regex = new Regex(GetRegexPatternFromKeyword(keyword));
        List<string> selection =
            _originalList.Where(s => regex.IsMatch(s)).ToList();
        listBox1.Items.Clear();
        listBox1.Items.AddRange(selection.ToArray());
    }
}

private static string GetRegexPatternFromKeyword(string keyword)
{
    string[] words =
        keyword.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries).Select(word => "(?=.*" + word.Replace(")", @"\)") + ")").ToArray();
    return string.Join("", words);
}

免责声明:在某些情况下,输入可能会“破坏”正则表达式模式

【讨论】:

  • 似乎有效。谢谢。但是正则表达式使用起来不是很慢吗?对我来说这并不重要,因为我最多有 100 件物品。
  • 有 100 件商品,我确实不会太担心。
【解决方案2】:

你的代码增加 l 太频繁了。比如;

带有搜索词 'aaa bbb' 的文本 'aaa aaa aaa' 会给出 3 的 l,因为每次找到 'aaa' 都会增加 l。因此,即使从未找到 'bbb',这也是一个匹配项。

您可以通过在每次搜索新的选择行之前删除找到的关键字拆分部分并重新创建关键字拆分来解决此问题(以及其他问题)。

l++;
break;

变成

l++
keywordSplit.RemoveAt[k];
break;

移动

string[] keywordSplit = keyword.Split(' ');

在你开始 k 循环之前

尽管我觉得可能有更好的方法来实现你想要的,代码更简洁、更快。

【讨论】:

  • 是的,我同意你的看法。但在这一点上,我只想让它工作,这样我就可以看到逻辑。之后我可以尝试优化它。我现在将测试您的更改。谢谢!
  • 那行不通。 keywordSplit 是一个数组,所以它不能删除这样的项目。
【解决方案3】:

我让它工作了。 @IvoTops 帮助我朝着正确的方向前进。只需先循环遍历所有关键字,然后再循环选择。

                for (int j = 0; j < keywordSplit.Length; j++)
                {
                    for (int k = 0; k < selectionSplit.Length; k++)
                    {
                        if (selectionSplit[k].ToLower().Contains(keywordSplit[j].ToLower()))
                        {
                            l++;
                            break;
                        }
                    }
                }

现在似乎可以正常工作了。

【讨论】:

    猜你喜欢
    • 2018-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-01
    • 1970-01-01
    相关资源
    最近更新 更多