改变选择的RTF
Change SelectedRTF
我有一个 richTextBox 和一个带有一些单词的正则表达式。有一次,我找到了所有我想把它们的颜色改成蓝色的词。我可以使用 SelectionColor = Blue
,但是当涉及到为数千个单词着色时,它变得非常慢。
经过一些搜索,我了解到更改 richTextBox 的 RTF 是更改文本的更快方法(例如它的大小 and/or 颜色)。
这是我未完成的代码:
MatchCollection matches = myRegex.Matches(richTextBox.text);
foreach (Match match in matches)
{
richTextBox.Select(match.Index, match.Length);
string addColor = @"{\colortbl ;\red0\green0\blue255;}" + Environment.NewLine;
richTextBox.SelectionColor = Color.Blue; //Must be replaced
}
我还发现在每种情况下(在我的情况下,整个文本使用相同的字体和相同的大小,只有一些单词的颜色发生变化)SelectedRtf
是:
{\rtf1\ansi\deff0{\fonttbl{\f0\fnil\fcharset0 Consolas;}}
\uc1\pard\lang1033\f0\fs18 word} // richTextBox.SelectedRtf
此外,使用 Selection.Color = Blue
将 SelectedRtf
更改为:
{\rtf1\ansi\deff0{\fonttbl{\f0\fnil\fcharset0 Consolas;}}
{\colortbl ;\red0\green0\blue255;} // The addColor string!
\uc1\pard\lang1033\f0\fs18 word}
为了得到上面的字符串,我使用了这个:richTextBox.SelectedRtf.Insert(59, addColor)
,所以我需要做的就是用它替换 SelectedRtf
。然而,经过一些尝试,似乎什么也没有发生。单词的颜色保持不变。有什么想法吗?
是的,这是可能的,而且比 'regular' 方式快两倍..:[=27=]
更改 3M 文本中的 30k 个单词需要 28 秒,而之前的 60 秒..
以下是我推荐的步骤,假设您的话在 richTextBox.Rtf
(*) 中是 可识别:
你可以创建你自己的颜色table,但让系统为你做似乎更安全:我作弊的方法是先给第一个字母上色,然后在给火柴上色后重置它..
我通过前景色索引的 rtf 代码将搜索词前后添加到 table 中。我的代码假设除了默认颜色之外只有一种额外的颜色。
如果你有更多,你应该跟踪和/或分析颜色table..
这是一个 RTF reference,顺便说一句..
我用 RichTextBox RTB
中的 RegEx
进行替换,如下所示:
string search "find me!";
RTB.SelectionStart = 0;
RTB.SelectionLength = 1;
RTB.SelectionColor = Color.HotPink;
Regex RX = new Regex(search);
MatchCollection matches = RX.Matches(RTB.Rtf);
RTB.Rtf = RX.Replace(RTB.Rtf, "\cf1 " + search + "\cf0 ");
RTB.SelectionStart = 0;
RTB.SelectionLength = 1;
RTB.SelectionColor = RTB.ForeColor;
(*) 请注意,像这样修改 Rtf
属性 假设您的搜索文本是 可识别的 在 Rtf
中。您可以而且应该通过在搜索 Rtf
和 Text
时比较匹配计数来检查这一点!当他们不同意时,您可能需要使用 'regular' 方式..
请注意,这仅涉及 Colors
。对于 Font
大小等,您必须以类似的方式添加 \fn
(样式表中的索引)命令..
更新: 我将上面的代码包装在一个扩展函数中,同时处理了更多的颜色、单词边界和一些检查..:
int colorWords(RichTextBox RTB, String searchWord, Color color)
{
string wordChar = @"\w*"; // or @"\b*" for stricter search
Regex RX = new Regex(wordChar + searchWord + wordChar);
RTB.SelectionStart = 0;
RTB.SelectionLength = 0;
RTB.SelectedText = "~"; // insert a dummy character
RTB.SelectionStart = 0;
RTB.SelectionLength = 1;
RTB.SelectionColor = color; // and color it
MatchCollection matches = null;
matches = RX.Matches(RTB.Text);
int textCount = matches.Count;
matches = RX.Matches(RTB.Rtf);
// we should not find more in the rtf code, less is ok
if (textCount < matches.Count) return -1;
if (matches.Count <= 0) return 0;
List<Color> colors = getRtfColorTable(RTB);
int cIndex = 1;
Color cRGB = Color.FromArgb(255, color);
if (colors.Contains(cRGB) )
cIndex = colors.FindIndex(x => x == cRGB) + 1;
RTB.Rtf = RX.Replace(RTB.Rtf, "\cf" + cIndex + " " + searchWord + "\cf0 ");
RTB.SelectionStart = 0;
RTB.SelectionLength = 1;
RTB.Cut(); // remove the dummy
return matches.Count;
}
这是一个从 Rtf 颜色中提取当前颜色的函数 table。 (希望完整的规范不是非常小,用两个简单的 IndexOf
来解决它有点乐观..;-)
List<Color> getRtfColorTable(RichTextBox RTB)
{ // \red255\green0\blue0;
List<Color> colors = new List<Color>();
string tabString = @"\colortbl ;";
int ct0 = RTB.Rtf.IndexOf(tabString);
if (ct0 >= 0)
{
ct0 += tabString.Length;
int ct1 = RTB.Rtf.IndexOf(@"}", ct0);
var table = RTB.Rtf.Substring(ct0, ct1 - ct0).Split(';');
foreach(string t in table)
{
var ch = t.Split('\');
if (ch.Length == 4)
{
int r = Convert.ToInt16(ch[1].Replace("red", ""));
int g = Convert.ToInt16(ch[2].Replace("green", ""));
int b = Convert.ToInt16(ch[3].Replace("blue", ""));
colors.Add(Color.FromArgb(255, r, g, b));
}
}
}
return colors;
}
这个例子是这样调用的:
colorWords(RTB, "<DIR>", Color.SaddleBrown);
colorWords(RTB, "Verzeichnis", Color.BlueViolet);
colorWords(RTB, "2012", Color.OrangeRed);
我有一个 richTextBox 和一个带有一些单词的正则表达式。有一次,我找到了所有我想把它们的颜色改成蓝色的词。我可以使用 SelectionColor = Blue
,但是当涉及到为数千个单词着色时,它变得非常慢。
经过一些搜索,我了解到更改 richTextBox 的 RTF 是更改文本的更快方法(例如它的大小 and/or 颜色)。
这是我未完成的代码:
MatchCollection matches = myRegex.Matches(richTextBox.text);
foreach (Match match in matches)
{
richTextBox.Select(match.Index, match.Length);
string addColor = @"{\colortbl ;\red0\green0\blue255;}" + Environment.NewLine;
richTextBox.SelectionColor = Color.Blue; //Must be replaced
}
我还发现在每种情况下(在我的情况下,整个文本使用相同的字体和相同的大小,只有一些单词的颜色发生变化)SelectedRtf
是:
{\rtf1\ansi\deff0{\fonttbl{\f0\fnil\fcharset0 Consolas;}}
\uc1\pard\lang1033\f0\fs18 word} // richTextBox.SelectedRtf
此外,使用 Selection.Color = Blue
将 SelectedRtf
更改为:
{\rtf1\ansi\deff0{\fonttbl{\f0\fnil\fcharset0 Consolas;}}
{\colortbl ;\red0\green0\blue255;} // The addColor string!
\uc1\pard\lang1033\f0\fs18 word}
为了得到上面的字符串,我使用了这个:richTextBox.SelectedRtf.Insert(59, addColor)
,所以我需要做的就是用它替换 SelectedRtf
。然而,经过一些尝试,似乎什么也没有发生。单词的颜色保持不变。有什么想法吗?
是的,这是可能的,而且比 'regular' 方式快两倍..:[=27=]
更改 3M 文本中的 30k 个单词需要 28 秒,而之前的 60 秒..
以下是我推荐的步骤,假设您的话在 richTextBox.Rtf
(*) 中是 可识别:
你可以创建你自己的颜色table,但让系统为你做似乎更安全:我作弊的方法是先给第一个字母上色,然后在给火柴上色后重置它..
我通过前景色索引的 rtf 代码将搜索词前后添加到 table 中。我的代码假设除了默认颜色之外只有一种额外的颜色。
如果你有更多,你应该跟踪和/或分析颜色table..
这是一个 RTF reference,顺便说一句..
我用 RichTextBox RTB
中的 RegEx
进行替换,如下所示:
string search "find me!";
RTB.SelectionStart = 0;
RTB.SelectionLength = 1;
RTB.SelectionColor = Color.HotPink;
Regex RX = new Regex(search);
MatchCollection matches = RX.Matches(RTB.Rtf);
RTB.Rtf = RX.Replace(RTB.Rtf, "\cf1 " + search + "\cf0 ");
RTB.SelectionStart = 0;
RTB.SelectionLength = 1;
RTB.SelectionColor = RTB.ForeColor;
(*) 请注意,像这样修改 Rtf
属性 假设您的搜索文本是 可识别的 在 Rtf
中。您可以而且应该通过在搜索 Rtf
和 Text
时比较匹配计数来检查这一点!当他们不同意时,您可能需要使用 'regular' 方式..
请注意,这仅涉及 Colors
。对于 Font
大小等,您必须以类似的方式添加 \fn
(样式表中的索引)命令..
更新: 我将上面的代码包装在一个扩展函数中,同时处理了更多的颜色、单词边界和一些检查..:
int colorWords(RichTextBox RTB, String searchWord, Color color)
{
string wordChar = @"\w*"; // or @"\b*" for stricter search
Regex RX = new Regex(wordChar + searchWord + wordChar);
RTB.SelectionStart = 0;
RTB.SelectionLength = 0;
RTB.SelectedText = "~"; // insert a dummy character
RTB.SelectionStart = 0;
RTB.SelectionLength = 1;
RTB.SelectionColor = color; // and color it
MatchCollection matches = null;
matches = RX.Matches(RTB.Text);
int textCount = matches.Count;
matches = RX.Matches(RTB.Rtf);
// we should not find more in the rtf code, less is ok
if (textCount < matches.Count) return -1;
if (matches.Count <= 0) return 0;
List<Color> colors = getRtfColorTable(RTB);
int cIndex = 1;
Color cRGB = Color.FromArgb(255, color);
if (colors.Contains(cRGB) )
cIndex = colors.FindIndex(x => x == cRGB) + 1;
RTB.Rtf = RX.Replace(RTB.Rtf, "\cf" + cIndex + " " + searchWord + "\cf0 ");
RTB.SelectionStart = 0;
RTB.SelectionLength = 1;
RTB.Cut(); // remove the dummy
return matches.Count;
}
这是一个从 Rtf 颜色中提取当前颜色的函数 table。 (希望完整的规范不是非常小,用两个简单的 IndexOf
来解决它有点乐观..;-)
List<Color> getRtfColorTable(RichTextBox RTB)
{ // \red255\green0\blue0;
List<Color> colors = new List<Color>();
string tabString = @"\colortbl ;";
int ct0 = RTB.Rtf.IndexOf(tabString);
if (ct0 >= 0)
{
ct0 += tabString.Length;
int ct1 = RTB.Rtf.IndexOf(@"}", ct0);
var table = RTB.Rtf.Substring(ct0, ct1 - ct0).Split(';');
foreach(string t in table)
{
var ch = t.Split('\');
if (ch.Length == 4)
{
int r = Convert.ToInt16(ch[1].Replace("red", ""));
int g = Convert.ToInt16(ch[2].Replace("green", ""));
int b = Convert.ToInt16(ch[3].Replace("blue", ""));
colors.Add(Color.FromArgb(255, r, g, b));
}
}
}
return colors;
}
这个例子是这样调用的:
colorWords(RTB, "<DIR>", Color.SaddleBrown);
colorWords(RTB, "Verzeichnis", Color.BlueViolet);
colorWords(RTB, "2012", Color.OrangeRed);