查找包含正则表达式匹配字符串的DOM元素

时间:2011-10-12 21:42:37

标签: javascript regex search dom

我需要在HTML页面上找到与特定正则表达式匹配的所有文本片段(也就是说,我需要忽略标记以使'< span>First name: < /span>< br/>< b>John< /b>'匹配'First name: John'),然后突出显示这些找到的片段(通过用新元素装饰并应用自定义css样式)并能够找到这些片段,例如能够将这些滚动到视图中。 功能类似于Skype浏览器插件在页面上找到的电话号码所做的事情。

4 个答案:

答案 0 :(得分:2)

您可以递归地向下看DOM,查看元素的 textContent innerText 属性(视情况而定),或者可以使用< EM>的getElementsByTagName 。无论哪种方式,一旦确定了文本和父元素,就需要弄清楚如何替换它。

如果字符串被分割为一个或多个其他元素,您对替换文档结构的要求是什么?

答案 1 :(得分:2)

您可以使用jQuery selectors获取包含<b>的{​​{1}}代码,该代码位于包含John的{​​{1}}代码之后,然后应用式:

<span>

以下是一个正在运行的示例:http://jsfiddle.net/XzwNj/

答案 2 :(得分:0)

由于该线程似乎是该主题的最佳规范,详细说明了 Rob's answer,因此您可以遍历所有节点并针对其每个子文本内容测试正则表达式模式。

这应该很慢,但可以用于调试目的。

SELECT 
'SELECT '||
RTRIM(
NVL2(SUM(c1),'c1,','') ||
NVL2(SUM(c2),'c2,','') ||
NVL2(SUM(c3),'c3,','') ||
NVL2(SUM(c4),'c4,','')
,',')||' FROM tab1;' FROM tab1;

STMT                                                           
---------------------------------------------------------------
CREATE OR REPLACE VIEW tab1_v AS SELECT c1,c3,c4 FROM tab1;
const findNodesByTextMatch = (
  pattern,
  root=document.body
) => 
  [...root.querySelectorAll("*")].filter(e => 
    [...e.childNodes].some(e =>
      e.nodeType === Node.TEXT_NODE && 
      pattern.test(e.textContent)
    )
  )
;

const nodes = findNodesByTextMatch(
  /baz\d/, document.querySelector("#root")
);
console.log(nodes);

为了处理跨标签模式,您可以运行遍历并构建文本内容字符串,将它们向上传递到树并将它们粘合在一起,直到正则表达式第一次匹配为止。例如:

<div id="root">
  <div>
    <div>
      <p>foobar</p>
      <p>foo baz</p>
    </div>
  </div>
  <div>
    <div>
      <p>foo bar</p>
      <p>foobaz42</p>
      <p>baz9</p>
      <p>quux</p>
    </div>
  </div>
</div>
const findNodesByTextMatch = (
  pattern,
  root=document.body
) => {
  const result = [];
  
  (function walk(root) {
    if (root.nodeType === Node.TEXT_NODE) {
      return root.textContent;
    }
    
    const childText = [...root.childNodes].map(walk).join("");
    
    if (pattern.test(childText)) {
      result.push(root);
      return "";
    }
    
    return childText;
  })(root);
  
  return result;
};

const nodes = findNodesByTextMatch(
  /baz\d/, document.querySelector("#root")
);
console.log(nodes.map(e => e.textContent));

有了这些节点,就可以拼凑出 Jake Archibald's fiddle 中的技术来找出正则表达式匹配的位置并创建一个范围来注入包装器元素。这段代码一团糟,效率肯定非常低,但我目前没有时间清理它,所以将其视为概念验证。

<div id="root">
  <div>
    <div>
      <p>foobar</p>
      <p>foo b<b><span><i>a</i>z</span>2</b>4</p>
    </div>
  </div>
  <div>
    <div>
      <p>foo bar</p>
      <p>foo<b>b</b>az<span>42</span></p>
      <p>baz9</p>
      <p>quux</p>
    </div>
  </div>
</div>
const findNodesByTextMatch = (
  pattern,
  root=document.body
) => {
  const result = [];
  
  (function walk(root) {
    if (root.nodeType === Node.TEXT_NODE) {
      return root.textContent;
    }
    
    const childText = [...root.childNodes]
      .map(walk).join("")
    ;
    
    if (pattern.test(childText)) {
      result.push(root);
      return "";
    }
    
    return childText;
  })(root);
  return result;
};

const pattern = /baz\d+/;
const nodes = findNodesByTextMatch(
  pattern, document.querySelector("#root")
);
nodes.forEach(e => {
  const iter = document.createNodeIterator(
    e, NodeFilter.SHOW_TEXT
  );
  let nodes = [];
  
  while (true) {
    const textNode = iter.nextNode();
    
    if (!textNode) {
      return;
    }
    
    nodes.push(textNode);
    const toText = nodes => 
      nodes.map(e => e.nodeValue).join("")
    ;
    
    if (pattern.test(toText(nodes))) {
      for (var i = 1; 
           pattern.test(toText(nodes.slice(i))); i++)
      ;

      nodes = nodes.slice(i - 1);
      const lastNode = nodes[nodes.length-1];

      const result = pattern.exec(toText(nodes));
      const matchStart = result.index;
      const matchEnd = matchStart + result[0].length - 1;
      const totalLength = nodes.reduce((a, e) =>
        a + e.textContent.length, 0
      );

      const range = document.createRange();
      range.setStart(nodes[0], matchStart);
      const rangeEnd = lastNode.textContent.length - 
        (totalLength - (matchEnd + 1))
      ;
      range.setEnd(lastNode, rangeEnd);
      const span = document.createElement("span");
      span.style.background = "#ff6";
      span.appendChild(range.extractContents());
      range.insertNode(span);
    }
  }
});

答案 3 :(得分:-1)

你尝试过这样的事吗?

document.body.innerHTML.replace(/<\/?[^>]+>/g, '')