简体   繁体   English

如何在 C# windows 表单 RichTextBox 中突出显示 HTML 语法?

[英]How to highlight HTML syntax in C# windows form RichTextBox?

I am writing a c# Html editor application, in which you type the code in a RichTextBox control.我正在编写一个 c# Html 编辑器应用程序,您可以在其中的 RichTextBox 控件中键入代码。 I want the RichTextBox to behave like notepad++ and other code editors in which the Html syntax gets highlighted in colors, like this for example:我希望 RichTextBox 的行为像 notepad++ 和其他代码编辑器,其中 Html 语法在 colors 中突出显示,例如:

例子

How can I establish this in C# windows form RichTextBox?如何在 RichTextBox 的 C# windows 中建立这个? I have searched almost everywhere and didn't find anything that helped me.我几乎到处搜索,但没有找到任何对我有帮助的东西。 This is what I tried so far but I doesn't give the result I want:这是我到目前为止尝试过的,但我没有给出我想要的结果:

private void SyntaxHighlight()
        {
            string[] tags = { "html","head","body","a","b","img","strong","p","h1","h2","h3","h4","h5","h6","embed","iframe","span","form",
                            "button","input","textarea","br","div","style","script","table","tr","td","th","i","u","link","meta","title"};
            foreach (string s in tags)
            {
                richTextBox1.Find("<" + s); 
                richTextBox1.SelectionColor = Color.Blue;
                richTextBox1.Find(">");
                richTextBox1.SelectionColor = Color.Blue;
            }

            string[] attributes = { "href","src","height","width","rowspan","colspan","target","style","onclick","id","name","class"};
            foreach (string s in attributes)
            {
                richTextBox1.Find(s + "=");
                richTextBox1.SelectionColor = Color.Red;
            }
        }

Can someone help me?有人能帮我吗? What should I write inside the SyntaxHighlight() method?我应该在 SyntaxHighlight() 方法中写什么? can someone give me the appropriate code?有人可以给我适当的代码吗? Thank you谢谢

Within your code you are only finding the 1st occurrence of the HTML tag and highlighting it. 在您的代码中,您只会发现HTML标记的第一个出现并将其突出显示。 But instead you should loop through the entire rich text content to finding proceeding occurrences of the same text. 但是,您应该遍历整个富文本内容,以查找同一文本的后续出现。 I just did quick mock based on your exact code, please check it out. 我只是根据您的确切代码进行了快速模拟,请检查一下。

    private void highlightHTMLText()
    {
        string[] tags = { "html","head","body","a","b","img","strong","p","h1","h2","h3","h4","h5","h6","embed","iframe","span","form",
                        "button","input","textarea","br","div","style","script","table","tr","td","th","i","u","link","meta","title"};
        foreach (string s in tags)
        {
            findAndHighlight("<" + s, Color.Blue);
            findAndHighlight("</" + s, Color.Blue);
            findAndHighlight(">", Color.Blue);
        }

        string[] attributes = { "href", "src", "height", "width", "rowspan", "colspan", "target", "style", "onclick", "id", "name", "class" };
        foreach (string s in attributes)
        {
            findAndHighlight(s + "=", Color.Red);
        }
    }

    private void findAndHighlight(string sSearchStr, Color oColor)
    {
        int index = richTextBox1.Text.IndexOf(sSearchStr);
        while (index != -1)
        {
            richTextBox1.Select(index, sSearchStr.Length);
            richTextBox1.SelectionColor = oColor;

            index = richTextBox1.Text.IndexOf(sSearchStr, index + sSearchStr.Length);
        }
    }

Further as per this answer you should be able to make use of the same utility library Scintilla used by Notepad++ itself. 进一步根据答案,您应该能够使用Notepad ++本身使用的相同实用程序库Scintilla As pointed out you do not need to re-invent the wheel, but as a developer I obviously prefer my own util (it is just me ;) ). 如前所述,您不需要重新发明轮子,但是作为开发人员,我显然更喜欢自己的util(就是我;))。 Hope this helps. 希望这可以帮助。

Find doesn't move a cursor, it returns the location of the first match. 查找不会移动光标,它会返回第一个匹配项的位置。 Try this instead: 尝试以下方法:

How to select text from the RichTextBox and then color it? 如何从RichTextBox中选择文本,然后为其着色?

A little late to the party but, after wanting to create my own offline version of CodePen, I implemented my own version of html syntax highlighting following CodePen's theme.晚会有点晚了,但在想创建自己的离线版本的 CodePen 之后,我按照 CodePen 的主题实现了自己的 html 语法高亮版本。

This does syntax highlighting and markup formatting, though the formatting depends on whether or not your html is well-formed.这会进行语法突出显示和标记格式化,但格式化取决于您的 html 是否格式正确。

Just add this as a class for your RichTextBox, instantiate it accordingly and call it within whichever event works for you (I'm using it with the RTB's double_click event but that does eliminate double-click text selection).只需将其添加为您的 RichTextBox 的 class,相应地实例化它并在适合您的任何事件中调用它(我将它与 RTB 的 double_click 事件一起使用,但这确实消除了双击文本选择)。 What I'm planning to do is add a timer, some boolean variables and work this within the key_up and key_down events to set the highlight update to be a bit more automatic and less intrusive on shortcuts.我打算做的是添加一个计时器,一些 boolean 变量,并在 key_up 和 key_down 事件中进行操作,以将突出显示更新设置得更自动一些,对快捷方式的干扰更少。 (which is hereby included below the class) (特此包含在类别下方)

    public void HighlightHTM(RichTextBox Htm_Input)
    {
        Htm_Input.Visible = false;
        #region store the original caret position + forecolor
        int originalIndex = Htm_Input.SelectionStart;
        int originalLength = Htm_Input.SelectionLength;
        Color originalColor = Color.FromArgb(200, 200, 200); // Grey
        #endregion
        #region try to format the markup
        try { Htm_Input.Text = XElement.Parse(Htm_Input.Text).ToString(); } catch { }
        #endregion
        #region match everything but puncutation and equals
        Regex e = new Regex(@"(.*?|=)[^\w\s]");
        MatchCollection eMatches = e.Matches(Htm_Input.Text);
        foreach (Match m in eMatches)
        {
            Htm_Input.SelectionStart = m.Groups[1].Index;
            Htm_Input.SelectionLength = m.Groups[1].Length;
            Htm_Input.SelectionColor = Color.FromArgb(221, 202, 126); // Yellow
        }
        #endregion
        #region match tags
        Regex t = new Regex(@"(<\w+|</\w+|/>|>)[^=]");
        MatchCollection tMatches = t.Matches(Htm_Input.Text, 0);
        foreach (Match m in tMatches)
        {
            Htm_Input.SelectionStart = m.Groups[1].Index;
            Htm_Input.SelectionLength = m.Groups[1].Length;
            Htm_Input.SelectionColor = Color.FromArgb(167, 146, 90); // Brown
        }
        #endregion
        #region match quotes
        Regex q = new Regex("\".*?\"");
        MatchCollection qMatches = q.Matches(Htm_Input.Text);
        foreach (Match m in qMatches)
        {
            Htm_Input.SelectionStart = m.Index;
            Htm_Input.SelectionLength = m.Length;
            Htm_Input.SelectionColor = Color.FromArgb(150, 179, 138); // Green
        }
        #endregion
        #region match inner html
        Regex h = new Regex(">(.+?)<");
        MatchCollection hMatches = h.Matches(Htm_Input.Text);
        foreach (Match m in hMatches)
        {
            Htm_Input.SelectionStart = m.Groups[1].Index;
            Htm_Input.SelectionLength = m.Groups[1].Length;
            Htm_Input.SelectionColor = Color.FromArgb(200, 200, 200); // Grey
        }
        #endregion
        #region restoring the original colors, for further writing
        Htm_Input.SelectionStart = originalIndex;
        Htm_Input.SelectionLength = originalLength;
        Htm_Input.SelectionColor = originalColor; // Light Grey
        #endregion
        Htm_Input.Focus();
        Htm_Input.Visible = true;
    }

Happy coding!编码愉快!

Edit: I should also mention that.doctype breaks formatting as it's not exactly xml-friendly in the context of "well-formed", For my purposes, all tags including body and relevant closings.编辑:我还应该提到 that.doctype 破坏了格式,因为它在“格式良好”的上下文中并不完全是 xml 友好的,为了我的目的,所有标签包括正文和相关的关闭。 css and js links are added programmatically at page save so only markup within the body tags are worked with inside the html RTB. css 和 js 链接是在页面保存时以编程方式添加的,因此在 html RTB 中仅使用正文标签内的标记。 This eliminates that problem.这消除了那个问题。

You'll notice that this relies exclusively on Regex rather than on hard-coded tags and properties.您会注意到这完全依赖于 Regex 而不是硬编码的标签和属性。 I did this because tags and properties have a tendency to pop on and off the w3 scene quite often.我这样做是因为标签和属性有一种经常在 w3 场景中出现和消失的趋势。 That would force a dev to continually have to go back and edit those strings to remove deprecated tags / properties or to add new.这将迫使开发人员不断地返回 go 并编辑这些字符串以删除不推荐使用的标签/属性或添加新的。 Not optimal.不是最优的。

I also thought it prudent to go ahead and include the instantiation / usage examples to make this a bit more plug&play.我还认为提前 go 并包括实例化/使用示例以使其更即插即用是明智的。

Above public Main(), instantiate like so:在 public Main() 之上,像这样实例化:

    #region Class Instantiation
    SyntaxHighlight syntax = new SyntaxHighlight();
    #endregion

... and, within your chosen event handler, call it like so: ...并且,在您选择的事件处理程序中,这样称呼它:

    private void htm_input_DoubleClick(object sender, EventArgs e)
    {
        syntax.HighlightHTM(Htm_Input);
    }

Naturally, adding a SaveFileDialog and an OpenFileDialog pretty much provides this the functionality of your very own, albeit very basic, html editor.自然地,添加一个 SaveFileDialog 和一个 OpenFileDialog 几乎可以提供您自己的功能,尽管非常基本,html 编辑器。 Toss in a WebBrowser control and apply the RTB's text as the WebBrowser's source and you've upgraded to live-view.放入 WebBrowser 控件并将 RTB 的文本应用为 WebBrowser 的源,您就升级到了实时视图。

In the very least, this should serve as a viable reference for syntax highlighting in general.至少,这应该作为一般语法突出显示的可行参考。 It really just boils down to identifying patterns and manipulating their colors so, for example, this will work effectively with css, javascript and even C# with some light adjusting of the pattern identification parameters.它实际上归结为识别模式并操纵它们的 colors,因此,例如,这将有效地与 css、javascript 甚至 C# 一起工作,只需对模式识别参数进行一些轻微调整。

The following is how I setup the automatic refresh with key_up / key_down and a timer set to 1000 ms:以下是我如何使用 key_up / key_down 设置自动刷新并将计时器设置为 1000 毫秒:

    #region Globals
    int r = 0;
    bool refresh = false;
    #endregion
    private void Htm_Input_KeyUp(object sender, KeyEventArgs e)
    {
        refresh = true; // enter refresh cycle
    }
    private void Htm_Input_KeyDown(object sender, KeyEventArgs e)
    {
        refresh = false; // abort refresh cycle
    }
    private void Timer_Refresh_Tick(object sender, EventArgs e)
    {
        // check if refresh cycle is entered, refresh at 3 seconds or reset the counter if aborted
        if (refresh) { if (r == 3) { syntax.HighlightHTM(Htm_Input); refresh = false; r = 0; } r++; } else { r = 0; }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM