Home > Software engineering >  Highlight / color text in a RichTextBox using a pattern
Highlight / color text in a RichTextBox using a pattern

Time:12-03

I'm trying to create a colorized RichTextBox based on a pattern.

The text is:

Hey, This{Red} IS A {Cyan}sample. The {Green}color is green color

Each { } contains a color which is a style for next words:

Hey, This IS Asample. The color is green color

Hey, This default color.

IS A should be Red color.

sample. The should be Cyan color.

color is green color should be green.

Here this is my code:

// Hey, This{Red} IS A {Cyan}sample. The {Green}color is green color
// shown text should be:
// Hey, This IS A sample. The color is green

const string OriginalText = "Hey, This{Red} IS A {Cyan}sample. The {Green}color is green color";
const string ShownText = "Hey, This IS A sample. The color is green color";
const string Pattern = "(?<=\\{)(.*?)(?=\\})";

rtbMain.Text = ShownText;

rtbMain.SelectAll();
rtbMain.SelectionColor = Color.Black;
rtbMain.SelectionBackColor = Color.White;
Regex regex = new(Pattern, RegexOptions.IgnoreCase);
MatchCollection matches = regex.Matches(OriginalText);

if (matches.Count > 0)
{
    var rtbText = rtbMain.Text;
    var length = ShownText.Length;
    var allMatches = new List<Match>();

    for (int i = 0; i < matches.Count; i  )
    {
        var m = matches[i];
        allMatches.Add(m);
        Match nextMatch = null;
        if (matches.Count > i   1)
        {
            nextMatch = matches[i   1];
        }
        var sum = GetSum();
        var start = m.Index;
        var currentLength = m.Length;
        if (nextMatch != null)
        {
            var end = nextMatch.Index - start- sum;
            rtbMain.Select(start- 1, end);
        }
        else
        {
            var currentIndex = OriginalText.IndexOf(m.Value);
            rtbMain.Select(length - currentIndex, (length - currentIndex) - sum);
        }
        rtbMain.SelectionColor = GetColor(m.Value);
    }
    int GetSum()
    {
        return allMatches!.Select(m => m.Value.Length - 1).Sum();
    }
    Color GetColor(string color)
    {
        return Color.FromName(color);
    }
}
else
{
    Debug.WriteLine("No matches found");
}

Since RichTextBox doesn't have the color tags, I don't know how to calculate the correct position of index/length.

Screen shot:

sample result

CodePudding user response:

You could also match the end position of the string you're parsing, then, when looping the Matches collection, you just need to calculate the current position inside the string, considering the length of each match.

With a slightly modified regex, the Index and Length of each Match refer to a matched tag (e.g., {green}), and each value in Group 1 is the name of a Color.

Something like this:
(note that just SelectionColor is used here, since I'm appending a new string to the Control on each iteration. The new string added is actually already a Selection, so there's no need to set the selection's length explicitly)

string originalText = 
    "Hey, This{Red} IS A {Cyan}sample. The {Green}color is green color\n"  
    "plus other text {blue} and some more {orange}colors";

string pattern = @"\{(.*?)\}|$";
var matches = Regex.Matches(originalText, pattern, RegexOptions.IgnoreCase);
int currentPos = 0;

foreach (Match m in matches) {
    someRichTextBox.AppendText(originalText.Substring(currentPos, m.Index - currentPos));

    currentPos = m.Index   m.Length;
    someRichTextBox.SelectionColor = Color.FromName(m.Groups[1].Value);
};
someRichTextBox.SelectionColor = someRichTextBox.ForeColor;

Resulting in:

RichTextBox pattern colors

  • Related