如何return RichTextBox中特定单词的精确范围
How to return the exact range of a specific word in RichTextBox
尝试 select 并为 WPF Richtextbox 中的特定单词着色,但我的方法 select 只是单词的前 5 个字母。索引 0,1 和 2 似乎是空字符串,尽管我的 rtb 中的第一个单词是 "private" 并且之前没有空字符串。
导致此问题的原因是什么?
public void FormatRtbText(RichTextBox rtb)
{
int x, y;
string str = "private";
var text = new TextRange(rtb.Document.ContentStart, rtb.Document.ContentEnd).Text;
x = text.IndexOf(str);
y = x + str.Length;
var range = new TextRange(rtb.Document.ContentStart.GetPositionAtOffset(x), rtb.Document.ContentStart.GetPositionAtOffset(y));
range.ApplyPropertyValue(TextElement.ForegroundProperty, Brushes.Red);
}
GetPositionAtOffset
在计算偏移量时将 3 个东西视为符号:
An opening or closing tag for the TextElement element.
A UIElement element contained in an InlineUIContainer or BlockUIContainer. Note
that such a UIElement is always counted as exactly one symbol; any
additional content or elements contained by the UIElement are not
counted as symbols.
A 16-bit Unicode character inside of a text Run
element.
这里的前两个符号是 Paragraph
和 Run
元素。因此,您的 TextRange
是您想要的后面的两个符号。此代码应该工作。 (这段代码所做的只是跳过符号,直到下一个符号是文本。)
TextPointer start = rtb.Document.ContentStart;
while (start.GetPointerContext(LogicalDirection.Forward) != TextPointerContext.Text)
{
start = start.GetNextContextPosition(LogicalDirection.Forward);
if (start == null) return;
}
...
var range = new TextRange(start, start.GetPositionAtOffset(y));
我发现 wpf rtf 框返回的偏移量几乎没有价值。他们没有考虑文本框需要的隐藏字符。框中的每个新段落、图像等都将添加更多隐藏字符,这些字符会扭曲偏移量。
这是我搜索结束到插入符号位置的匹配项的方法。
private TextRange FindText(string findText)
{
var fullText = DoGetAllText();
if (string.IsNullOrEmpty(findText) || string.IsNullOrEmpty(fullText) || findText.Length > fullText.Length)
return null;
var textbox = GetTextbox();
var leftPos = textbox.CaretPosition;
var rightPos = textbox.CaretPosition;
while (true)
{
var previous = leftPos.GetNextInsertionPosition(LogicalDirection.Backward);
var next = rightPos.GetNextInsertionPosition(LogicalDirection.Forward);
if (previous == null && next == null)
return null; //can no longer move outward in either direction and text wasn't found
if (previous != null)
leftPos = previous;
if (next != null)
rightPos = next;
var range = new TextRange(leftPos, rightPos);
var offset = range.Text.IndexOf(findText, StringComparison.InvariantCultureIgnoreCase);
if (offset < 0)
continue; //text not found, continue to move outward
//rtf has broken text indexes that often come up too low due to not considering hidden chars. Increment up until we find the real position
var findTextLower = findText.ToLower();
var endOfDoc = textbox.Document.ContentEnd.GetNextInsertionPosition(LogicalDirection.Backward);
for (var start = range.Start.GetPositionAtOffset(offset); start != endOfDoc; start = start.GetPositionAtOffset(1))
{
var result = new TextRange(start, start.GetPositionAtOffset(findText.Length));
if (result.Text?.ToLower() == findTextLower)
{
return result;
}
}
}
}
如果您想突出显示匹配项,只需将此方法更改为 void 并在找到匹配项时执行此操作即可:
textbox.Selection.Select(result.Start, result.End);
尝试 select 并为 WPF Richtextbox 中的特定单词着色,但我的方法 select 只是单词的前 5 个字母。索引 0,1 和 2 似乎是空字符串,尽管我的 rtb 中的第一个单词是 "private" 并且之前没有空字符串。
导致此问题的原因是什么?
public void FormatRtbText(RichTextBox rtb)
{
int x, y;
string str = "private";
var text = new TextRange(rtb.Document.ContentStart, rtb.Document.ContentEnd).Text;
x = text.IndexOf(str);
y = x + str.Length;
var range = new TextRange(rtb.Document.ContentStart.GetPositionAtOffset(x), rtb.Document.ContentStart.GetPositionAtOffset(y));
range.ApplyPropertyValue(TextElement.ForegroundProperty, Brushes.Red);
}
GetPositionAtOffset
在计算偏移量时将 3 个东西视为符号:
An opening or closing tag for the TextElement element.
A UIElement element contained in an InlineUIContainer or BlockUIContainer. Note that such a UIElement is always counted as exactly one symbol; any additional content or elements contained by the UIElement are not counted as symbols.
A 16-bit Unicode character inside of a text Run element.
这里的前两个符号是 Paragraph
和 Run
元素。因此,您的 TextRange
是您想要的后面的两个符号。此代码应该工作。 (这段代码所做的只是跳过符号,直到下一个符号是文本。)
TextPointer start = rtb.Document.ContentStart;
while (start.GetPointerContext(LogicalDirection.Forward) != TextPointerContext.Text)
{
start = start.GetNextContextPosition(LogicalDirection.Forward);
if (start == null) return;
}
...
var range = new TextRange(start, start.GetPositionAtOffset(y));
我发现 wpf rtf 框返回的偏移量几乎没有价值。他们没有考虑文本框需要的隐藏字符。框中的每个新段落、图像等都将添加更多隐藏字符,这些字符会扭曲偏移量。
这是我搜索结束到插入符号位置的匹配项的方法。
private TextRange FindText(string findText)
{
var fullText = DoGetAllText();
if (string.IsNullOrEmpty(findText) || string.IsNullOrEmpty(fullText) || findText.Length > fullText.Length)
return null;
var textbox = GetTextbox();
var leftPos = textbox.CaretPosition;
var rightPos = textbox.CaretPosition;
while (true)
{
var previous = leftPos.GetNextInsertionPosition(LogicalDirection.Backward);
var next = rightPos.GetNextInsertionPosition(LogicalDirection.Forward);
if (previous == null && next == null)
return null; //can no longer move outward in either direction and text wasn't found
if (previous != null)
leftPos = previous;
if (next != null)
rightPos = next;
var range = new TextRange(leftPos, rightPos);
var offset = range.Text.IndexOf(findText, StringComparison.InvariantCultureIgnoreCase);
if (offset < 0)
continue; //text not found, continue to move outward
//rtf has broken text indexes that often come up too low due to not considering hidden chars. Increment up until we find the real position
var findTextLower = findText.ToLower();
var endOfDoc = textbox.Document.ContentEnd.GetNextInsertionPosition(LogicalDirection.Backward);
for (var start = range.Start.GetPositionAtOffset(offset); start != endOfDoc; start = start.GetPositionAtOffset(1))
{
var result = new TextRange(start, start.GetPositionAtOffset(findText.Length));
if (result.Text?.ToLower() == findTextLower)
{
return result;
}
}
}
}
如果您想突出显示匹配项,只需将此方法更改为 void 并在找到匹配项时执行此操作即可:
textbox.Selection.Select(result.Start, result.End);