3

我使用 RichTextBox 来测试 REGEX 表达式,代码如下:

rtbMain.SelectAll();
rtbMain.SelectionColor = Color.Black;
rtbMain.SelectionBackColor = Color.White;
Regex regex = new Regex(txtRegexPattern.Text, regexOptions);
Match matches = regex.Match(txtTest.Text);
while (matches.Success)
{
    rtbMain.Select(matches.Index, match.Length);
    rtbMain.SelectionColor = Color.Red;
    rtbMain.SelectionBackColor = Color.Black;
}

但是一旦有超过几千(1000+)个字符要突出显示,这种方法就会变得太慢。我知道我可以延迟处理,因此代码让用户有机会输入整个正则表达式,但我仍然认为 RichTextBox 突出显示工作太慢。

我在 Google 上搜索了加快当前解决方案的不同方法和方法,但我没有运气。我注意到有一些文本编辑器允许“语法高亮”(如 ScintillNET、Avalon 等),但它们使用 XML 作为输入,所以我认为将它们用于我的项目(在每个 KeyUp 事件上生成 XML)不会t 是“最佳实践”。

我在这里找到并测试了一个“快速彩色文本框”:https ://github.com/PavelTorgashov/FastColoredTextBox ...但是这个问题是它在使用自己的换行符和选项卡时替换了粘贴内容字符,我不能在 REGEX 测试器中使用它。

有没有更快的方法来突出显示所有匹配项,也许使用不同的用户控件?

编辑:

方法 1:生成底层 RTF 文档会更快吗?我试过了,但特殊字符有一些问题,所以我可以测试整个文档的突出显示,但在一行中使用普通字符似乎工作得很快。我暂停了这方面的工作,因为我读到构建 RTF 可能非常困难,而且我认为我不能使用任何现有的 RTF 库。

方法 2:我只能获得 RichTextBox 的显示部分,所以我想只突出显示该部分。我想这会显着减少处理(取决于 RTB 大小),但我需要在每次用户滚动时触发突出显示;我不确定这是否能很好地工作并创造一个体面的用户体验,所以还没有尝试过。

有人会推荐上述任何方法或其他方法吗?

4

3 回答 3

2

第一的:

RichTextBox 有一个固有的问题:它在.NET 中非常慢。我找到了一个解决方案,如何让它快 120 倍。也许你试试看:C# RichEditBox 的性能极慢(加载 4 分钟)已解决

第二:

从头开始构建 RTF 代码是最快的解决方案。看看我关于 codeproject 的文章。有一个可重用的 RTF 构建器类:http: //www.codeproject.com/Articles/23513/SQL-Editor-for-Database-Developers

于 2013-09-07T03:50:40.367 回答
1

我怀疑您是否While以不正确的方式设置了循环。

尝试这样的事情:(未经测试,但会给你一个如何解决这个问题的想法)

rtbMain.SelectAll();
rtbMain.SelectionColor = Color.Black;
rtbMain.SelectionBackColor = Color.White;
Regex regex = new Regex(txtRegexPattern.Text, regexOptions);
MatchCollection matches = regex.Matches(txtTest.Text);

if(matches.Count > 0)
{
   foreach(Match m in matches)
   {
      rtbMain.Select(m.Index, m.Length);
      rtbMain.SelectionColor = Color.Red;
      rtbMain.SelectionBackColor = Color.Black;
   }
}
else
{
   Debug.Print("No matches found"); // See "Output" Window
}

编辑

我做了一些与突出显示 RTF 文本相关的解决方法,我发现的第一件事是该过程花费的大部分时间是以下几行:

  rtbMain.SelectionColor = Color.Red;
  rtbMain.SelectionBackColor = Color.Black;

我尝试使用SelectionStartSelectionEnd属性来选择文本.Select(),但没有观察到任何变化。

关于与构建等效RTF有关的第一点,我也尝试过,但是很难构建等效的RTF,因为那里有很多东西需要处理。如果可以完成,处理时间将小于 1.5 秒,超过 31k 匹配(特定样本的基本测试结果)。

因此,我建议您通过THREADING执行此操作并将任务拆分为两个线程:

这是一个示例源代码:(在最坏的情况下,我发现大约 31341 个匹配项,处理过程需要 4 秒才能突出显示)

    // declare variables either globally or in the same method
    MatchCollection mcoll;
    Stopwatch s;
    int callbackCount = 0;
    List<Match> m1 = null;
    List<Match> m2 = null;

    private void btnHighlight_Click(object sender, EventArgs e)
    {
        //reset any exisiting formatting
        rtbMain.SelectAll();
        rtbMain.SelectionBackColor = Color.White;
        rtbMain.SelectionColor = Color.Black;
        rtbMain.DeselectAll();

        s = new Stopwatch();
        s.Start();

        Regex re = new Regex(@"(.)", RegexOptions.Compiled); // Notice COMPILED option
        mcoll = re.Matches(rtbMain.Text);

        // Break MatchCollection object into List<Matches> which is exactly half in size
        m1 = new List<Match>(mcoll.Count / 2);
        m2 = new List<Match>(mcoll.Count / 2);

        for (int k = 0; k < mcoll.Count; k++)
        {
            if (k < mcoll.Count / 2)
                m1.Add(mcoll[k]);
            else
                m2.Add(mcoll[k]);
        }

        Thread backgroundThread1 = new Thread(new ThreadStart(() => {
            match1(null, null);
        }));
        backgroundThread1.Start();

        Thread backgroundThread2 = new Thread(new ThreadStart(() =>
        {
            match2(null, null);
        }));
        backgroundThread2.Start();
    }

    public void match1(object obj, EventArgs e)
    {
        for (int i=0; i < m1.Count; i += 1)
        {
            if (rtbMain.InvokeRequired)
            {
                EventHandler d = new EventHandler(match1);
                rtbMain.Invoke(d);
            }
            else
            {
                rtbMain.Select(m1[i].Index, m1[i].Length);
                rtbMain.SelectionBackColor = Color.Black;
                rtbMain.SelectionColor = Color.Red;
            }
        }
        stopTimer();
    }

    public void match2(object obj, EventArgs e)
    {
        for (int j=0; j < m2.Count; j += 1)
        {
            if (rtbMain.InvokeRequired)
            {
                EventHandler d = new EventHandler(match2);
                rtbMain.Invoke(d);
            }
            else
            {
                rtbMain.Select(m2[j].Index, m2[j].Length);
                rtbMain.SelectionBackColor = Color.Black;
                rtbMain.SelectionColor = Color.Red;
            }
        }
        stopTimer();
    }

    void stopTimer()
    {
        callbackCount++;

        if (callbackCount == 2) // 2 because I am using two threads.
        {
            s.Stop();
            // Check Output Window
            Debug.Print("Evaluated in : " + s.Elapsed.Seconds.ToString());
        }
    }

由于您发布的操作大约需要 30 秒,因此希望 4 秒是可以忍受的,并且用户可以像RubularDerekSlager 的 .Net 正则表达式测试器那样的其他在线转换器那样通过一些加载屏幕来吸引用户。

不要忘记查看为什么 Regex.Compiled 首选

于 2013-06-04T04:50:30.117 回答
1

请在http://www.codeproject.com/Articles/3669/Expresso-A-Tool-for-Building-and-Testing-Regular-E查看 Expresso

多年来,我一直在使用这个程序来编辑和评估正则表达式。

于 2013-05-30T05:02:11.633 回答