获取相对于文本的IHTMLTxtRange位置

时间:2014-02-20 20:31:45

标签: c# browser webbrowser-control

我需要在WebBrowser控件中找出所选文本的位置。我可以通过

获得IHTMLTxtRange
        IHTMLDocument2 htmlDocument = BookReaderWeb.Document as IHTMLDocument2;
        IMarkupServices ms = (IMarkupServices) htmlDocument;
        IHTMLSelectionObject selection = htmlDocument.selection;
        if (selection == null) return;
        IHTMLTxtRange range = selection.createRange() as IHTMLTxtRange;

但我不知道如何获得相对于全文(不是html)的范围位置。 感谢。

更新


正如Noseratio建议的那样,我实现了以下代码:

        IHTMLDocument2 htmlDocument = BookReaderWeb.Document as IHTMLDocument2;
        var str = htmlDocument.body.outerText;
        IMarkupServices ms = (IMarkupServices) htmlDocument;
        IHTMLSelectionObject selection = htmlDocument.selection;
        if (selection == null) return;
        IHTMLTxtRange range = selection.createRange() as IHTMLTxtRange;
        dynamic body = htmlDocument.body;
        var bodyRange = body.createTextRange();
        bodyRange.moveToElementText(body);
        var bodyText = bodyRange.text;
        var counter = 0;
        while (bodyRange.compareEndPoints("StartToStart", range) != 0)
        {
            bodyRange.moveStart("character", 1);
            ++counter;
        }
        MessageBox.Show(str.Substring(counter, 20));

但它没有给出正确的结果。这个位置是向前放错的几个字符然后它应该是。它只发生在大型html文件上,它适用于较小的文件。看起来dom api将某种标签解释为字符可能..?

1 个答案:

答案 0 :(得分:3)

一种愚蠢的方法(为简单起见使用JavaScript表示法):

  1. document.body创建文字范围:
    var bodyRange = document.body.createTextRange(); bodyRange.moveToElementText(document.body);
    现在bodyRange.text对应全文。
  2. 使用bodyRange.moveStart("character", 1)一次向前移动一个字符,并将其开头与您选择的范围比较为bodyRange.compareEndPoints("StartToStart", range。当它们匹配时,您已在全文中找到了开头的位置。
  3. 执行bodyRange.collapse(true),这会将范围的结束移动到范围的开始。
  4. 使用bodyRange.moveEnd("character", 1)一次向前移动一个字符,并将其开头与您选择的范围开始比较bodyRange.compareEndPoints("EndToEnd", range)。当它们匹配时,您已在全文中找到了结尾的位置。
  5. 您可以通过为moveStart / moveEnd一次移动一个单词或一个句子来改进此算法,然后一次精确匹配一个字符。

    此外,还有一种更好的方法,它使用standard DOM Range and Selection API。我描述了它here

    已更新,请尝试对您的代码进行以下更新(未经测试):

    var tempRange = bodyRange.duplicate();
    while (bodyRange.compareEndPoints("StartToStart", range) != 0)
    {
        bodyRange.moveStart("character", 1);
         tempRange.setEndPoint("EndToStart", bodyRange);
        //tempRange.EndToStart(bodyRange);
        if (String.Compare(tempRange.text, ((String)bodyText).Substring(counter)) != 0)
          ++counter;
    }
    MessageBox.Show(str.Substring(counter, 20));