HTML和JS:使用<span>标记包含文档中的每个单词

Ble*_*oul 0 html javascript regex

我正在尝试使用Javascript来修改现有的HTML文档,以便我可以span使用带有计数器的标记包围网页中的每个文本单词.这是一个非常具体的问题,所以我将提供一个示例案例:

<body><p>hello, <br>
change this</p> 
<img src="lorempixel.com/200/200> <br></body></html>
Run Code Online (Sandbox Code Playgroud)

这应该改为:

  <body><p><span id="1">hello,</span>
  <br> <span id="2"> change</span><span id="3"> this</span> </p>
  <br> <img src="lorempixel.com/200/200> <br></body></html>
Run Code Online (Sandbox Code Playgroud)

我在思考或regex解决方案,但他们变得非常复杂,我不知道如何忽略标签和更改文本而不完全破坏页面.

任何想法赞赏!

sle*_*man 7

不要在原始HTML上使用正则表达式.仅在文本上使用它.这是因为正则表达式是一个无上下文解析器,但HTML是一种递归语言.您需要一个递归下降解析器来正确处理HTML.

首先是DOM的一些有用功能:

  1. document.body 是DOM的根
  2. DOM的每个节点都有一个childNodes数组(甚至是注释,文本和属性)
  3. 元素节点例如<span><h>不包含文本,而是包含包含文本的文本节点.
  4. 所有节点都具有nodeType属性,文本节点是类型3.
  5. 所有节点都有一个nodeValue属性,它根据节点的类型保存不同的东西.对于文本节点nodeValue包含实际文本.

因此,使用上面的信息,我们可以用跨度包围所有单词.

首先是一个简单的实用函数,它允许我们处理DOM:

// First a simple implementation of recursive descent,
// visit all nodes in the DOM and process it with a callback:
function walkDOM (node,callback) {
    if (node.nodeName != 'SCRIPT') { // ignore javascript
        callback(node);
        for (var i=0; i<node.childNodes.length; i++) {
            walkDOM(node.childNodes[i],callback);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我们可以遍历DOM并找到文本节点:

var textNodes = [];
walkDOM(document.body,function(n){
    if (n.nodeType == 3) {
        textNodes.push(n);
    }
});
Run Code Online (Sandbox Code Playgroud)

请注意,我这两步都是为了避免包含两次单词.

现在我们可以处理文本节点:

// simple utility functions to avoid a lot of typing:
function insertBefore (new_element, element) {
    element.parentNode.insertBefore(new_element,element);
}
function removeElement (element) {
    element.parentNode.removeChild(element);
}
function makeSpan (txt, attrs) {
    var s = document.createElement('span');
    for (var i in attrs) {
        if (attrs.hasOwnProperty(i)) s[i] = attrs[i];
    }
    s.appendChild(makeText(txt));
    return s;
}
function makeText (txt) {return document.createTextNode(txt)}

var id_count = 1;
for (var i=0; i<textNodes.length; i++) {
    var n = textNodes[i];
    var txt = n.nodeValue;
    var words = txt.split(' ');

    // Insert span surrounded words:
    insertBefore(makeSpan(words[0],{id:id_count++}),n);
    for (var j=1; j<words.length; j++) {
        insertBefore(makeText(' '),n); // join the words with spaces
        insertBefore(makeSpan(words[j],{id:id_count++}),n);
    }
    // Now remove the original text node:
    removeElement(n);
}
Run Code Online (Sandbox Code Playgroud)

你有它.它很麻烦但是100%安全 - 它永远不会破坏你网页中其他javascript标签.我上面的很多实用功能都可以用你选择的库替换.但是,不要把整个文档视为一个巨大的innerHTML字符串.除非您愿意在纯JavaScript中编写HTML解析器.