Javascript Regex替换html属性中的text not

m14*_*14t 13 javascript regex

我想要一个Javascript Regex来包装给定的start(<span>)和结束标记(即</span>)中给定的单词列表,但前提是该单词实际上是页面上的"可见文本",而不是在html属性中(例如链接的标题标记或<script></script>块内部.

我已经创建了一个基本设置的JS小提琴:http: //jsfiddle.net/4YCR6/1/

T.J*_*der 38

HTML过于复杂,无法使用正则表达式进行可靠的解析.

如果您希望在客户端执行此操作,则可以创建文档片段和/或断开连接的DOM节点(两者都不显示在任何位置)并使用HTML字符串对其进行初始化,然后遍历生成的DOM树并处理文本节点.(或者使用库来帮助你做到这一点,虽然它实际上非常简单.)

这是一个DOM行走示例.这个例子比你的问题稍微简单一些,因为它只是更新文本,它没有向结构中添加新元素(在spans中包含部分文本涉及更新结构),但它应该让你前进.关于最后需要改变什么的说明.

var html =
    "<p>This is a test.</p>" +
    "<form><input type='text' value='test value'></form>" +
    "<p class='testing test'>Testing here too</p>";
var frag = document.createDocumentFragment();
var body = document.createElement('body');
var node, next;

// Turn the HTML string into a DOM tree
body.innerHTML = html;

// Walk the dom looking for the given text in text nodes
walk(body);

// Insert the result into the current document via a fragment
node = body.firstChild;
while (node) {
  next = node.nextSibling;
  frag.appendChild(node);
  node = next;
}
document.body.appendChild(frag);

// Our walker function
function walk(node) {
  var child, next;

  switch (node.nodeType) {
    case 1:  // Element
    case 9:  // Document
    case 11: // Document fragment
      child = node.firstChild;
      while (child) {
        next = child.nextSibling;
        walk(child);
        child = next;
      }
      break;
    case 3: // Text node
      handleText(node);
      break;
  }
}

function handleText(textNode) {
  textNode.nodeValue = textNode.nodeValue.replace(/test/gi, "TEST");
}
Run Code Online (Sandbox Code Playgroud)

实例

您需要做出的更改将在handleText.具体而言,nodeValue您需要:而不是更新,您需要:

  • 找到nodeValue字符串中每个单词开头的索引.
  • 使用Node#splitText分割文本节点到最多三个文本节点(您匹配的文本之前的部分,该部分你匹配的文本,并按照您的匹配文本的部分).
  • 使用document.createElement以创建新的span(这是真的只是span = document.createElement('span')).
  • 用于在第三个文本节点(包含匹配文本后面的文本的节点)之前Node#insertBefore插入新span文本; 这没关系,如果你并不需要创建第三个节点,因为你匹配的文本是在文本节点的结束,只是通过在null作为refChild.
  • 使用Node#appendChild所述第二文本节点(具有匹配的文本)移入span.(无需先将其从父项中删除; appendChild为您做到这一点.)

  • 有趣的事实:近五年后,他们在[Drumpfinator Chrome扩展程序](http://drumpfinator.com/)中使用此代码连接到*Last Week Tonight*与John Oliver.爆笑! (14认同)
  • 还为云对接提供动力!https://github.com/panicsteve/cloud-to-butt/blob/master/Source/content_script.js (2认同)

Tim*_*own 10

TJ Crowder的回答是正确的.我已经进一步改进了代码:这是一个完整的示例,适用于所有主流浏览器.我之前已经在Stack Overflow上发布了这些代码的变体(例如这里这里),并且使它很好并且通用,所以我(或其他任何人)不必更改它以重用它.

jsFiddle示例:http://jsfiddle.net/7Vf5J/38/

码:

// Reusable generic function
function surroundInElement(el, regex, surrounderCreateFunc) {
    // script and style elements are left alone
    if (!/^(script|style)$/.test(el.tagName)) {
        var child = el.lastChild;
        while (child) {
            if (child.nodeType == 1) {
                surroundInElement(child, regex, surrounderCreateFunc);
            } else if (child.nodeType == 3) {
                surroundMatchingText(child, regex, surrounderCreateFunc);
            }
            child = child.previousSibling;
        }
    }
}

// Reusable generic function
function surroundMatchingText(textNode, regex, surrounderCreateFunc) {
    var parent = textNode.parentNode;
    var result, surroundingNode, matchedTextNode, matchLength, matchedText;
    while ( textNode && (result = regex.exec(textNode.data)) ) {
        matchedTextNode = textNode.splitText(result.index);
        matchedText = result[0];
        matchLength = matchedText.length;
        textNode = (matchedTextNode.length > matchLength) ?
            matchedTextNode.splitText(matchLength) : null;
        // Ensure searching starts at the beginning of the text node
        regex.lastIndex = 0;
        surroundingNode = surrounderCreateFunc(matchedTextNode.cloneNode(true));
        parent.insertBefore(surroundingNode, matchedTextNode);
        parent.removeChild(matchedTextNode);
    }
}

// This function does the surrounding for every matched piece of text
// and can be customized  to do what you like
function createSpan(matchedTextNode) {
    var el = document.createElement("span");
    el.style.color = "red";
    el.appendChild(matchedTextNode);
    return el;
}

// The main function
function wrapWords(container, words) {
    // Replace the words one at a time to ensure "test2" gets matched
    for (var i = 0, len = words.length; i < len; ++i) {
        surroundInElement(container, new RegExp(words[i]), createSpan);
    }
}

wrapWords(document.getElementById("container"), ["test2", "test"]);
Run Code Online (Sandbox Code Playgroud)