如何在不计算扩展实体的情况下找到标记(元素)的字符串索引?

How do I find the string index of a tag (an element) without counting expanded entities?

本文关键字:元素 索引 字符串 计算 扩展 情况下 实体      更新时间:2023-09-26

我有一大块文本,我希望能够选择,通过其startindexendindex存储所选部分。(例如,在word中选择or将得到startindex 1和endindex 2。)

这一切工作正常,但我有一个问题与HTML实体,如&(&)。

我创建了一个问题包含的小案例。您可以在下面的图中看到,如果您选择&以外的任何内容,startIndex会膨胀,因为它不会将&计算为单个字符,而是将&计算为5个字符:

是否有一种方法可以使它正确计数特殊字符,如&,而不会搞砸索引?

http://jsfiddle.net/Eqct4/

JavaScript


$(document).ready(function() {
    $('#textBlock').mouseup(function() {
        var selectionRange = window.getSelection();
        if (!selectionRange.isCollapsed) {
            selectedText = selectionRange.getRangeAt(0).toString();
        }
        document.getElementById('textBlock').setAttribute('contenteditable', true);
        document.execCommand('strikethrough', false);
        var startIndex = $('#textBlock').html().indexOf('<strike>');
         $('#startindex').html('the startindex is: ' + startIndex);
        done();
    });
});
function done() {
    document.getElementById('textBlock').setAttribute('contenteditable', false);
    document.getSelection().removeAllRanges();
    removeStrikeFromElement($('#textBlock'));
}
function removeStrikeFromElement (element) {
    element.find('strike').each(function() {
        jQuery(this).replaceWith(removeStrikeFromElement(jQuery(this)));
    });
    return element.html();
}

我认为/知道这与$('#textBlock').html()用来做indexOf而不是text()有关。获得startendindex的最好方法是通过选定的文本来获取<strike>,因为execCommand让我这样做,它是一个从未在应用程序中使用过的HTML标签。

如果你真的想使用你的代码,只是稍微修改一下,你可以用可见的等效替换所有特殊字符,同时保留html标签…将startIndex的声明更改为:

var startIndex = $('#textBlock').html().replace(/&amp;/g, "&").replace(/&quot;/g, "'"").indexOf('<strike>');

你可以在replaces()函数后面加上你想算作普通字符的其他特殊字符,而不是它们的HTML版本。在我的例子中,我替换了&和"字符。

有更多的优化可能在你的代码,这是一个简单的方法来解决你的问题。

希望这有助于一点,看到这里的分叉小提琴http://jsfiddle.net/vQNyv/

问题

使用html()返回:

This is a cool test &amp; <strike>stuff like</strike> that

使用text()将返回:

This is a cool test & stuff like that
因此,html()是必要的,以便看到字符串<strike>,但是当然,所有特殊实体都被转义了,它们应该是。有很多方法可以解决这个问题,但是想象一下,如果文本描述的是HTML本身,会发生什么:
Use the <strike></strike> tags to strike out text.

在这种情况下,想要的解释,

Use the &lt;strike&gt;&lt;/strike&gt; tag to strike out text.

这就是为什么唯一正确的方法是遍历DOM节点。


jQuery/DOM解决方案

这是我的解决方案的jsFiddle,这里是代码:

jQuery.fn.indexOfTag = function (tag) {
    var nodes = this[0].childNodes;
    var chars = 0;
    for (var i = 0; nodes && i < nodes.length; i++) {
        var node = nodes[i];
        var type = node.nodeType;
        if (type == 3 || type == 4 || type == 5) {
            // alert('advancing ' + node.nodeValue.length + ' chars');
            chars += node.nodeValue.length;
        } else if (type == 1) {
            if (node.tagName == tag.toUpperCase()) {
                // alert('found <' + node.tagName + '> at ' + chars + ', returning');
                return chars;
            } else {
                // alert('found <' + node.tagName + '>, recursing');
                var subIndexOfTag = $(node).indexOfTag(tag);
                if (subIndexOfTag == -1) {
                    // alert('did not find <' + tag.toUpperCase() + '> in <' + node.tagName + '>');
                    chars += $(node).text().length;
                } else {
                    // alert('found <' + tag.toUpperCase() + '> in <' + node.tagName + '>');
                    chars += subIndexOfTag;
                    return chars;
                }
            }
        }
    }
    return -1;
}

取消注释alert() s以深入了解发生了什么。以下是nodeType s的参考。


jQuery/DOM解决方案计数outerHTML根据你的评论,我认为你是在说你确实想要计算HTML标签(按字符计算),而不是HTML实体。这是函数本身的新jsFiddle,这是它应用于你的问题的新jsFiddle