首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >RichTextBox在有趣的地方查找我的搜索词

RichTextBox在有趣的地方查找我的搜索词
EN

Stack Overflow用户
提问于 2014-01-24 21:44:10
回答 1查看 155关注 0票数 3

我正在尝试在WPF RichTextBox中查找字符串的实例。我现在所拥有的几乎可以正常工作,但它突出显示了文档中错误的部分。

代码语言:javascript
复制
private int curSearchLocation;

private void FindNext_Click(object sender, RoutedEventArgs e)
{
    TextRange text = new TextRange(RichEditor.Document.ContentStart, RichEditor.Document.ContentEnd);
    var location = text.Text.IndexOf(SearchBox.Text, curSearchLocation, StringComparison.CurrentCultureIgnoreCase);
    if (location < 0)
    {
        location = text.Text.IndexOf(SearchBox.Text, StringComparison.CurrentCultureIgnoreCase);
    }
    if (location >= 0)
    {
        curSearchLocation = location + 1;
        RichEditor.Selection.Select(text.Start.GetPositionAtOffset(location), text.Start.GetPositionAtOffset(location + SearchBox.Text.Length));
    }
    else
    {
        curSearchLocation = 0;
        MessageBox.Show("Not found");
    }
    RichEditor.Focus();
}

这是我搜索“document”时出现的结果:

这是因为GetPositionAtOffset在其偏移量中包含了非文本元素,如开始和结束标记,这不是我想要的。我找不到忽略这些元素的方法,也找不到直接获得我想要的文本的TextPointer的方法,这也可以解决问题。

如何让它突出显示正确的文本?

EN

回答 1

Stack Overflow用户

发布于 2014-01-30 04:51:24

不幸的是,TextRange.Text去掉了非文本字符,因此在这种情况下,由IndexOf计算的偏移量将稍微太小。这是主要的问题。

我试图解决你的问题,并找到了一个有效的解决方案,即使我们在许多段落中设置了文本格式,也能很好地工作。

这个CodeProject Article提供了很多帮助。所以,也请阅读这篇文章。

代码语言:javascript
复制
int curSearchLocation;
private void FindNext_Click(object sender, RoutedEventArgs e)
{
    TextRange text = new TextRange(RichEditor.Document.ContentStart, RichEditor.Document.ContentEnd);
    var location = text.Text.IndexOf(SearchBox.Text, curSearchLocation, StringComparison.CurrentCultureIgnoreCase);
    if (location < 0)
    {
        location = text.Text.IndexOf(SearchBox.Text, StringComparison.CurrentCultureIgnoreCase);
    }
    if (location >= 0)
    {
        curSearchLocation = location + 1;
        Select(location, SearchBox.Text.Length);
    }
    else
    {
        curSearchLocation = 0;
        MessageBox.Show("Not found");
    }
    RichEditor.Focus();                                   
}        

public void Select(int start, int length)
{
    TextPointer tp = RichEditor.Document.ContentStart;

    TextPointer tpLeft = GetPositionAtOffset(tp, start, LogicalDirection.Forward);
    TextPointer tpRight = GetPositionAtOffset(tp, start + length, LogicalDirection.Forward);
    RichEditor.Selection.Select(tpLeft, tpRight);            
}

private TextPointer GetPositionAtOffset(TextPointer startingPoint, int offset, LogicalDirection direction)
{
    TextPointer binarySearchPoint1 = null;
    TextPointer binarySearchPoint2 = null;

    // setup arguments appropriately
    if (direction == LogicalDirection.Forward)
    {
        binarySearchPoint2 = this.RichEditor.Document.ContentEnd;

        if (offset < 0)
        {
            offset = Math.Abs(offset);
        }
    }

    if (direction == LogicalDirection.Backward)
    {
        binarySearchPoint2 = this.RichEditor.Document.ContentStart;

        if (offset > 0)
        {
            offset = -offset;
        }
    }

    // setup for binary search
    bool isFound = false;
    TextPointer resultTextPointer = null;

    int offset2 = Math.Abs(GetOffsetInTextLength(startingPoint, binarySearchPoint2));
    int halfOffset = direction == LogicalDirection.Backward ? -(offset2 / 2) : offset2 / 2;

    binarySearchPoint1 = startingPoint.GetPositionAtOffset(halfOffset, direction);
    int offset1 = Math.Abs(GetOffsetInTextLength(startingPoint, binarySearchPoint1));

    // binary search loop

    while (isFound == false)
    {
        if (Math.Abs(offset1) == Math.Abs(offset))
        {
            isFound = true;
            resultTextPointer = binarySearchPoint1;
        }
        else
            if (Math.Abs(offset2) == Math.Abs(offset))
            {
                isFound = true;
                resultTextPointer = binarySearchPoint2;
            }
            else
            {
                if (Math.Abs(offset) < Math.Abs(offset1))
                {
                    // this is simple case when we search in the 1st half
                    binarySearchPoint2 = binarySearchPoint1;
                    offset2 = offset1;

                    halfOffset = direction == LogicalDirection.Backward ? -(offset2 / 2) : offset2 / 2;

                    binarySearchPoint1 = startingPoint.GetPositionAtOffset(halfOffset, direction);
                    offset1 = Math.Abs(GetOffsetInTextLength(startingPoint, binarySearchPoint1));
                }
                else
                {
                    // this is more complex case when we search in the 2nd half
                    int rtfOffset1 = startingPoint.GetOffsetToPosition(binarySearchPoint1);
                    int rtfOffset2 = startingPoint.GetOffsetToPosition(binarySearchPoint2);
                    int rtfOffsetMiddle = (Math.Abs(rtfOffset1) + Math.Abs(rtfOffset2)) / 2;
                    if (direction == LogicalDirection.Backward)
                    {
                        rtfOffsetMiddle = -rtfOffsetMiddle;
                    }

                    TextPointer binarySearchPointMiddle = startingPoint.GetPositionAtOffset(rtfOffsetMiddle, direction);
                    int offsetMiddle = GetOffsetInTextLength(startingPoint, binarySearchPointMiddle);

                    // two cases possible
                    if (Math.Abs(offset) < Math.Abs(offsetMiddle))
                    {
                        // 3rd quarter of search domain
                        binarySearchPoint2 = binarySearchPointMiddle;
                        offset2 = offsetMiddle;
                    }
                    else
                    {
                        // 4th quarter of the search domain
                        binarySearchPoint1 = binarySearchPointMiddle;
                        offset1 = offsetMiddle;
                    }
                }
            }
    }

    return resultTextPointer;
}

int GetOffsetInTextLength(TextPointer pointer1, TextPointer pointer2)
{
    if (pointer1 == null || pointer2 == null)
        return 0;

    TextRange tr = new TextRange(pointer1, pointer2);

    return tr.Text.Length;
}

希望这段代码能在你的情况下工作。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/21334281

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档