将搜索结果从文本文件排序到列表框中

时间:2010-07-15 16:59:01

标签: c# regex winforms search listbox

我所拥有的是用户键入字符串的文本框。字符串看起来像这样: G32:04:20:40

然后用户点击搜索按钮。然后程序必须打开一个文本文件,并搜索“最近”的五个字符串到他们输入的字符串,并将它们显示在列表框中。

我会尽可能多地定义“最近的字符串”(最有可能使用一个非常复杂的例子)。

文本文件中包含的数据如下所示:

G32:63:58:11 JG01
G32:86:98:30 JG01
G33:50:05:11 JG06
G33:03:84:12 JG05
G34:45:58:11 JG07
G35:45:20:41 JG01
G35:58:20:21 JG03

因此,如果用户键入字符串:

G33:89:03:20

五个最接近的结果应该显示在列表框中,如下所示:

G33:50:05:11 JG06
G33:03:84:12 JG05
G32:86:98:30 JG01
G32:63:58:11 JG01
G34:45:58:11 JG07

我应该在这一点上指出,字符串是坐标,“JG”之后的值表示该坐标处某事物的值。

我到达那些5的方式是逐段浏览弦乐。所以用户输入“G33”,所以我发现所有那些在开始时都有G33的人 - 如果没有,那么我找到最接近G33的人。然后它是“89”所以我发现所有那些下一部分是“89”如果没有,那么最接近89更好等等。

我需要知道的是我该如何做到这一点?我已经构建了可视化组件,并且我还有代码来处理类似的事情,但是当涉及到这个时,我真的很难过。你现在可以说,我对C#很新,但我正在学习:)。

编辑:搜索代码

private void btnSearch_Click(object sender, EventArgs e)
        {
            lstResult.Items.Clear();

            if (txtSearch.Text == String.Empty)
            {
                MessageBox.Show("The textbox is empty, there is nothing to search.",
                    "Textbox empty", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            else
            {
                this.CheckFormatting();
            }

        }

        private long GetIndexForCoord(string coord)
        {
            // gets out a numerical value for each coordinate to make it easier to compare
            Regex m_regex = new Regex("\\d\\d:\\d\\d:\\d\\d:\\d\\d");
            string cleaned = m_regex.Match(coord).Value;
            cleaned = cleaned.Replace(':', '0');
            return Convert.ToInt64(cleaned);
        }

        private List<string> GetResults(string coord)
        {
            // gets out the 5 closest coordinates
            long index = GetIndexForCoord(coord);

            // First find the 5 closest indexes to the one we're looking for
            List<long> found = new List<long>();
            while (found.Count < 5)
            {
                long closest = long.MaxValue;
                long closestAbs = long.MaxValue;
                foreach (long i in m_indexes)
                {
                    if (!found.Contains(i))
                    {
                        long absIndex = Math.Abs(index - i);
                        if (absIndex < closestAbs)
                        {
                            closest = i;
                            closestAbs = absIndex;
                        }
                    }
                }
                if (closest != long.MaxValue)
                {
                    found.Add(closest);
                }
            }

            // Then use those indexes to get the coordinates from the dictionary
            List<string> s = new List<string>();
            foreach (long i in found)
            {
                s.Add(m_dic[i]);
            }
            return s;
        }

        private void CheckFormatting()
        {
            StringReader objReader = new StringReader(txtSearch.Text);

            bool FlagCheck = true;

                if (!Regex.IsMatch(txtSearch.Text,
                    "G3[0-9]{1}:[0-9]{2}:[0-9]{2}:[0-9]{2}"))
                {
                    FlagCheck = false;
                }

            if (FlagCheck == true)
            {
                this.CheckAndPopulate();
            }
            else
            {
                MessageBox.Show("Your search coordinates are not formatted correctly.",
                       "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void CheckAndPopulate()
        {
            StreamReader objReader = new StreamReader("Jumpgate List.JG");
            List<String> v = new List<String>();
            do
            {
                v.Add(objReader.ReadLine());
            }
            while (objReader.Peek() != -1);

            objReader.Close();

            foreach (string c in v)
            {
                long index = GetIndexForCoord(c);
                m_dic.Add(index, c);
                m_indexes.Add(index);
            }

            List<string> results = GetResults(txtSearch.Text);
            foreach (string c in results)
            {
                lstResult.Items.Add(c);
            }
        }

1 个答案:

答案 0 :(得分:3)

编辑:添加建议的代码以读入文件。最后还有一个解释 Edit2:添加,如果检查添加到词典/列表以处理重复项。

请注意,此代码几乎肯定是非常低效的(除非可能意外)并且需要清理并且需要添加错误处理等,但它可能为您提供了编写更好代码的起点。 您可能想查看k-nearest neighbor algorithm以找出正确的方法。

我假设开头的字母总是G,并且坐标的所有4个部分总是2个数字。

将以下2添加到您的班级/表单中:

    Dictionary<long, string> m_dic = new Dictionary<long, string>();
    List<long> m_indexes = new List<long>();

然后使用以下代码初始化它们(我假设您已经将所有坐标读入一个名为v的字符串数组中,每个项目有一个坐标):

foreach (string c in v)
{
    long index = GetIndexForCoord(c);
    if(!m_dic.ContainsKey(index))
    {
        m_dic.Add(index, c);
        m_indexes.Add(index);
    }
}

然后添加以下两种方法:

// gets out a numerical value for each coordinate to make it easier to compare
private long GetIndexForCoord(string coord)
{
    Regex m_regex = new Regex("\\d\\d:\\d\\d:\\d\\d:\\d\\d");
    string cleaned = m_regex.Match(coord).Value;
    cleaned = cleaned.Replace(':', '0');
    return Convert.ToInt64(cleaned);
}
// gets out the 5 closest coordinates
private List<string> GetResults(string coord)
{
    long index = GetIndexForCoord(coord);

    // First find the 5 closest indexes to the one we're looking for
    List<long> found = new List<long>();
    while (found.Count < 5)
    {
            long closest = long.MaxValue;
            long closestAbs = long.MaxValue;
            foreach (long i in m_indexes)
            {
                if (!found.Contains(i))
                {
                    long absIndex = Math.Abs(index - i);
                    if (absIndex < closestAbs)
                    {
                        closest = i;
                        closestAbs = absIndex;
                    }
                }
            }
            if (closest != long.MaxValue)
            {
                found.Add(closest);
            }
    }

    // Then use those indexes to get the coordinates from the dictionary
    List<string> s = new List<string>();
    foreach (long i in found)
    {
        s.Add(m_dic[i]);
    }
    return s;
}

最后,当用户将您在该数据中发送的数据输入到方法中时:

List<string> results  = GetResults(lookingFor);

然后,您可以使用结果填充列表框。

代码的工作原理是将每个坐标转换为一个名为index的数值(因为它更容易使用),然后将所有坐标添加到以索引为键的字典中。
当它查找最近的坐标时,它会比较您正在查找的索引与每个先前存储的索引之间的值之间的差异,以找到最接近的5个(它使用Math.Abs方法,以便它可以获得差异而不必担心负数)。这是非常低效的,因为它为你想要找到的每个坐标遍历每个值一次(所以如果你的列表包含1000个坐标,你想要找到最接近的5个,它将通过内循环5000次,我假设通过改进代码可能会减少到1000次,我建议查看接近此答案顶部的wiki链接以获得更好的算法。)