如何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.

这里的前两个符号是 ParagraphRun 元素。因此,您的 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);