【问题标题】:counting text node recursively using javascript使用javascript递归计算文本节点
【发布时间】:2011-08-05 03:42:10
【问题描述】:

假设我有这样的标记

<html id="test">
<body>
Some text node.
<div class="cool"><span class="try">This is another text node.</span></div>
Yet another test node.
</body>
</html>

我的 js 代码

function countText(node){
 var counter = 0;
 if(node.nodeType === 3){
     counter+=node.nodeValue.length;
     countText(node);
 }
 else{}
}

现在如果我想计算文本节点

console.log("count text : " + countText(document.getElementById("test"));

这应该返回给我计数,但它不起作用,而且我应该在 else 条件下放置什么。 我从来没有使用过nodeType,所以在使用它时遇到了问题。任何帮助将不胜感激。

【问题讨论】:

  • 请注意,给定相同的 HTML,不同的浏览器可能会创建不同数量的文本节点。
  • @RobG 你能简单解释一下这种行为吗...

标签: javascript textnode


【解决方案1】:

您的代码中有几处错误:

  • 您的 HTML 格式不正确。
  • 您正在将文本附加到您的 counter 而不是增加它。
  • 您永远不会遍历 a 节点的子节点,您总是将同一个节点传递给递归调用。
  • 如果节点不是文本节点,您什么都不做。

这将起作用:

function countText(node){
    var counter = 0;
    if(node.nodeType === 3){
        counter++;
    }
    else if(node.nodeType === 1) { // if it is an element node, 
       var children = node.childNodes;    // examine the children
       for(var i = children.length; i--; ) {
          counter += countText(children[i]);
       }
    }
    return counter;  
}

alert(countText(document.body));

DEMO

哪个数字对应哪个节点类型can be found here


更新:

如果要统计字数,则必须先将每个文本节点拆分为字词。在下文中,我假设单词由空格分隔:

if(node.nodeType === 3){
    counter = node.nodeValue.split(/\s+/g).length;
}

更新 2

我知道你想使用递归函数,但如果你只想计算单词,那么有一个更简单、更有效的方法:

function countWords(node){
    // gets the text of the node and all its descendants
    var text = node.innerText || node.textContent
    return text.split(/\s+/g).length;
}

【讨论】:

  • 实际上没有必要为任何其他节点类型进行测试。如果它是一个文本节点,请计算它。然后在任何情况下,如果存在的话,遍历所有的孩子。
  • @Felix 我不担心标记...但是您的函数计数为 3 而文本计数为 12 .....所以我认为必须使用 node.value.length 而不是计数器但你的 else 语句是有道理的,因为元素最常见的 nodeType
  • @user429035:啊,所以你想数单词?这与计算文本节点不同。在上面的示例中,有 3 个文本节点。您应该清楚地说明这一点(我的脚本计数为 3,而不是 2 个文本节点)。请看我的更新。顺便说一句,有效标记很重要,因为只有这样您才能知道您的脚本是否有效。例如。在您的 HTML 中,您缺少一个右引号 &lt;span class="try&gt;,其后果是浏览器不会呈现剩余的标记。
  • +1 @Felix...抱歉给您带来了困惑...是的,这是一个错误 class="try" 错过了双引号...
  • @user429035:不用担心 :) 另请参阅我的第二次更新。有一种比使用递归更有效的方法......当然你想要什么;)
【解决方案2】:

你想要类似的东西

function countTextNodes(node) {
    var n = 0;
    if(node.nodeType == 3)
        n = 1;
    for(var i = 0; i < node.childNodes.length; ++i)
        n += countTextNodes(node.childNodes[i]);
    return n;
}

这可以压缩成更紧凑的代码,但我在这里是为了易读性。

在要计算文本节点的根上调用它。例如,要计算整个文档中的文本节点,您可能需要调用 countTextNodes(document.getDocumentElement())

【讨论】:

  • @chomp 谢谢!但我不想使用 for 循环,而只想递归地执行它......并且类型有效,因为我认为它的 nodeType..
  • @user429035:它仍然是递归的。你必须使用for循环,否则,你想如何在子节点上调用函数?您必须遍历孩子。
  • 请注意,循环只遍历直接子代,递归调用每个子代上的countTextNodes 并累积结果。正如@Felix Kling 所建议的那样,如果没有这样的迭代,您会发现不可能实现您的目标。另外,您对nodeType 的看法是正确的。抱歉打错了!
  • @chomp 和 @Felix 同意...我必须按照 @Felix 的建议在 else 语句中使用 for 循环,这是有道理的
  • 请使用=== Node.TEXT_NODE而不是幻数3
猜你喜欢
  • 2017-08-22
  • 2021-08-15
  • 2020-02-21
  • 1970-01-01
  • 1970-01-01
  • 2014-08-12
  • 2015-08-31
  • 2019-05-15
  • 2010-08-12
相关资源
最近更新 更多