Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/447.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/html/84.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 哪些HTML元素表示分词?_Javascript_Html_Dom - Fatal编程技术网

Javascript 哪些HTML元素表示分词?

Javascript 哪些HTML元素表示分词?,javascript,html,dom,Javascript,Html,Dom,我正在开发一个Chrome扩展,它从任何访问过的页面中提取所有单词,并为文本中的各种单词添加标记。我可以使用 document.body.innerText 并将结果拆分为单词,但这并不提供添加标记所需的关于给定单词的位置(即DOM元素/节点)的关键信息。使用时也存在同样的问题 document.body.textContent 此外,它还有一个缺点,即它包含不可见的项,例如脚本标记内容 因此,我编写了一个迭代函数,它基本上是逐步遍历DOM元素(在树的深度优先遍历中)并累积从中获得的文本 nod

我正在开发一个Chrome扩展,它从任何访问过的页面中提取所有单词,并为文本中的各种单词添加标记。我可以使用

document.body.innerText

并将结果拆分为单词,但这并不提供添加标记所需的关于给定单词的位置(即DOM元素/节点)的关键信息。使用时也存在同样的问题

document.body.textContent

此外,它还有一个缺点,即它包含不可见的项,例如脚本标记内容

因此,我编写了一个迭代函数,它基本上是逐步遍历DOM元素(在树的深度优先遍历中)并累积从中获得的文本

node.data

其中node是遇到的任何文本节点;这允许我记录结果文本中字符范围与DOM中相应节点之间的映射,结果字符串似乎与document.body.textContent的字符串完全匹配。(另外,这允许我过滤掉脚本标记等)

我所面临的问题是,textContent不能正确地打断单词,而且(也许?)在分词的地方不明确。例如:

一段

下一段

生成字符串“一个段落下一个段落”,即两个元素之间没有分隔字符,我的代码只检测3个单词,而不是4个。textContent出错(没有空格),而innerText正确(插入空格)

此外,始终在节点/元素之间放置空格是不正确的,因为:

这是一个internet,不是intranet。

应产生“互联网”一词,但不包含空格(即,不应将其分为两个词)。(此处的理由是,如果分机正在查找“internet”一词,则应标记该词;如果分机正在查找“net”一词,则不应标记该词,因为对用户而言,该词显示为一个词“internet”。)


“innerText”属性正确返回带空格的文本,或者返回不带空格的文本(看起来不合适)。在我的迭代方法中,我如何模拟通过DOM的步骤?是否定义了哪些元素(或元素组合/转换)在显示的文本中引入空白,哪些不引入空白?这是块显示还是内联显示元素的问题?

仔细查看了(再次感谢您的建议),我现在回到这个问题。innerText的规则有些复杂,在我的例子中,这些规则中的大部分都是不需要的,因为我只对分词出现的位置感兴趣,而对分词是否正确不感兴趣。我还觉得,在我的例子中,一个简单的解决方案在100个案例中有99个案例是正确的,比一个在所有案例中都正确的复杂解决方案要好。因此,考虑到这一点,我创建了以下简单函数:

function getNodeText(node) 
{
  // If we have nothing to process, return the empty string.
  if (!node) return '';
  
  // Is this a text node? If so simply grab the text from it.
  if (node.nodeType === Node.TEXT_NODE) return node.data;
  
  // If this was not a text node (see above) and it is not an element 
  // node then nothing further to do, just return an empty string.
  if (node.nodeType !== Node.ELEMENT_NODE) return '';
  
  // Some elements we do not want to handle at all. Just returning empty.
  const tagsToAvoid = ['SCRIPT', 'NOSCRIPT', 'STYLE', 'OBJECT', 'IFRAME'];
  if (tagsToAvoid.includes(node.tagName)) return '';    
  
  // A line break nodes simply inserts a space
  if (node.tagName == 'BR') return ' ';
  
  // Block-level tags 
  const blockTags = 
    ['ADDRESS', 'ARTICLE', 'ASIDE', 'BLOCKQUOTE', 'CANVAS', 'DD', 'DIV', 
     'DL', 'DT', 'FIELDSET', 'FIGCAPTION', 'FIGURE', 'FOOTER', 'FORM', 
     'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'HEADER', 'HR', 'LI', 'MAIN', 'NAV',
     'OL', 'P', 'PRE', 'SECTION', 'TABLE', 'TD', 'TR', 'TFOOT', 'UL', 
     'VIDEO', 'TBODY', 'THEAD', 'COL', 'COLGROUP', 'TH', 'CAPTION'];
  
  // Whether to add whitespace around the text that is obtained
  // from iterating over the children. In typical cases there is no 
  // whitespace inserted, but block level nodes do get whitespace.
  const addSpaces = blockTags.includes(node.tagName);
  
  // Step through all children and get the text from them (recursively)
  let child = node.firstChild;
  let textFromChildren = '';
  while (child)
  {
    textFromChildren += getNodeText(child);
    child = child.nextSibling;
  }
  
  // Return the result, with added whitespace or not
  if (addSpaces) return ' ' + textFromChildren + ' ';
  else return textFromChildren;
}
注意,为了清楚起见,我省略了跟踪结果字符串的哪些部分来自哪些节点的代码(这很容易添加到上面)

有几点需要注意:

(1) 代码很慢。在长页面上,执行此操作可能需要数十毫秒,这可能比简单调用标准innerText慢十倍(后者通常比textContent慢)。我不清楚是否有简单的方法来加速代码;也许比我聪明的人可以对此发表评论


(2) 我认为,在某些方面,上述内容并不完全正确,因为它没有考虑到样式(例如,这可能会影响元素是以块还是以内联方式显示)。然而,希望是,对于绝大多数情况来说,这已经足够好了。(同样,其他在这一领域工作时间比我长的人可能更适合谈论这一点。)

仔细看了一下(再次感谢你的建议),我现在回到这个问题上来。innerText的规则有些复杂,在我的例子中,这些规则中的大部分都是不需要的,因为我只对分词出现的位置感兴趣,而对分词是否正确不感兴趣。我还觉得,在我的例子中,一个简单的解决方案在100个案例中有99个案例是正确的,比一个在所有案例中都正确的复杂解决方案要好。因此,考虑到这一点,我创建了以下简单函数:

function getNodeText(node) 
{
  // If we have nothing to process, return the empty string.
  if (!node) return '';
  
  // Is this a text node? If so simply grab the text from it.
  if (node.nodeType === Node.TEXT_NODE) return node.data;
  
  // If this was not a text node (see above) and it is not an element 
  // node then nothing further to do, just return an empty string.
  if (node.nodeType !== Node.ELEMENT_NODE) return '';
  
  // Some elements we do not want to handle at all. Just returning empty.
  const tagsToAvoid = ['SCRIPT', 'NOSCRIPT', 'STYLE', 'OBJECT', 'IFRAME'];
  if (tagsToAvoid.includes(node.tagName)) return '';    
  
  // A line break nodes simply inserts a space
  if (node.tagName == 'BR') return ' ';
  
  // Block-level tags 
  const blockTags = 
    ['ADDRESS', 'ARTICLE', 'ASIDE', 'BLOCKQUOTE', 'CANVAS', 'DD', 'DIV', 
     'DL', 'DT', 'FIELDSET', 'FIGCAPTION', 'FIGURE', 'FOOTER', 'FORM', 
     'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'HEADER', 'HR', 'LI', 'MAIN', 'NAV',
     'OL', 'P', 'PRE', 'SECTION', 'TABLE', 'TD', 'TR', 'TFOOT', 'UL', 
     'VIDEO', 'TBODY', 'THEAD', 'COL', 'COLGROUP', 'TH', 'CAPTION'];
  
  // Whether to add whitespace around the text that is obtained
  // from iterating over the children. In typical cases there is no 
  // whitespace inserted, but block level nodes do get whitespace.
  const addSpaces = blockTags.includes(node.tagName);
  
  // Step through all children and get the text from them (recursively)
  let child = node.firstChild;
  let textFromChildren = '';
  while (child)
  {
    textFromChildren += getNodeText(child);
    child = child.nextSibling;
  }
  
  // Return the result, with added whitespace or not
  if (addSpaces) return ' ' + textFromChildren + ' ';
  else return textFromChildren;
}
注意,为了清楚起见,我省略了跟踪结果字符串的哪些部分来自哪些节点的代码(这很容易添加到上面)

有几点需要注意:

(1) 代码很慢。在长页面上,执行此操作可能需要数十毫秒,这可能比简单调用标准innerText慢十倍(后者通常比textContent慢)。我不清楚是否有简单的方法来加速代码;也许比我聪明的人可以对此发表评论


(2) 我认为,在某些方面,上述内容并不完全正确,因为它没有考虑到样式(例如,这可能会影响元素是以块还是以内联方式显示)。然而,希望是,对于绝大多数情况来说,这已经足够好了。(同样,其他在这一领域工作时间比我长的人可能更适合谈论这一点。)

关于边距、填充、不可见边框、变换等呢。?您对
互联网
案例的预期结果是什么?类似于
互联网
,但不是
互联网
?有关于空格和javascript DOM遍历的规范。检查此MDN条目末尾的脚本,确保
innerText
插入空格的方式定义良好,并在中指定。@user4642212正确点。我编辑了这个问题,以表明事实上,就互联网而言