c#-有没有更快捷的方法突出显示正则表达式匹配项(RichTextBox)

c#-有没有更快捷的方法突出显示正则表达式匹配项(RichTextBox),c#,winforms,performance,richtextbox,highlight,C#,Winforms,Performance,Richtextbox,Highlight,我使用RichTextBox测试正则表达式,代码如下: 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.Su

我使用RichTextBox测试正则表达式,代码如下:

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高亮显示的工作速度太慢了

我在谷歌上搜索了不同的方法和途径来加速当前的解决方案,但我运气不好。我注意到有一些文本编辑器允许“语法突出显示”(如闪烁、Avalon等),但它们使用XML作为输入,因此我认为在我的项目中使用它们(在每个键控事件上生成XML)不是“最佳实践”

我在这里找到并测试了一个“快速着色文本框”:……但这个文本框的问题是,它在使用自己的新行和制表符时替换了粘贴内容,而我无法在REGEX tester中使用它

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

编辑:

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

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

是否有人推荐上述方法或其他方法?

请访问Expresso


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

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

尝试以下内容:(未经测试,但将为您提供解决此问题的方法)

编辑

我做了一些与突出显示RTF文本相关的变通方法,我发现这个过程所花费的时间主要是以下几行:

  rtbMain.SelectionColor = Color.Red;
  rtbMain.SelectionBackColor = Color.Black;
我尝试使用
SelectionStart
SelectionEnd
属性来选择文本,但没有发现任何更改

关于你的第一点,关于构造等价的RTF,我也尝试过,但是构造等价的RTF是困难的,因为有很多东西需要处理。如果能够完成,则处理时间约为<1.5秒,超过31k次匹配(特定样品的基本测试结果)

因此,我建议您通过线程化并将任务拆分为两个线程:

下面是一个示例源代码: (在最坏的情况下,我发现大约31341个匹配项,这个过程花了4秒钟突出显示)

//全局或在同一方法中声明变量
麦考尔;
秒表;
int callbackCount=0;
列表m1=空;
列表m2=空;
private void btnHighlight\u单击(对象发送者,事件参数e)
{
//重置任何现有格式
rtbMain.SelectAll();
rtbMain.SelectionBackColor=Color.White;
rtbMain.SelectionColor=Color.Black;
rtbMain.deceloseall();
s=新秒表();
s、 Start();
Regex re=new Regex(@“(.)”,RegexOptions.Compiled);//注意编译选项
mcoll=re.Matches(rtbMain.Text);
//将MatchCollection对象拆分为大小正好为一半的列表
m1=新列表(mcoll.Count/2);
m2=新列表(mcoll.Count/2);
for(int k=0;k{
match1(null,null);
}));
backgroundThread1.Start();
线程背景thread2=新线程(新线程开始(()=>
{
match2(null,null);
}));
backgroundThread2.Start();
}
公共无效匹配1(对象对象对象、事件参数)
{
对于(int i=0;i
由于您发布的操作大约需要30秒,所以希望4秒是可以忍受的,用户可以通过一些加载屏幕参与,就像其他在线转换器一样。
  rtbMain.SelectionColor = Color.Red;
  rtbMain.SelectionBackColor = Color.Black;
    // 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());
        }
    }