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:
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) {
[richTextBox].AppendText(originalText.Substring(currentPos, m.Index - currentPos));
currentPos = m.Index m.Length;
[richTextBox].SelectionColor = Color.FromName(m.Groups[1].Value);
};
[richTextBox].SelectionColor = [richTextBox].ForeColor;
Resulting in: