0

私は次のようにかなりうまく機能するjavascriptコードを持っています:

var rgx = /MyName/g;
var curInnerHTML = document.body.innerHTML;
curInnerHTML = curInnerHTML.replace(rgx, "<span><span class='myName'>MyNameReplace</span></span>");

問題は、HTML属性などに含まれているシナリオでも正規表現が一致することです。HTMLのコンテンツ内でのみ正規表現が見つかるように正規表現を変更するにはどうすればよいですか?たとえば、この文字列では

    <div class="someclass" title="MyName">
MyName
</div>

現在、次のようになります(title属性の変更に注意してください)。

        <div class="someclass" title="<span><span class='myName'>MyNameReplace</span</span>">
<span><span class='myName'>
    MyNameReplace</span></span>
    </div>

しかし、私はそれが必要です(タイトル属性はそのままにしておきます):

    <div class="someclass" title="MyName">
<span><span class='myName'>MyNameReplace</span></span>
</div>
4

1 に答える 1

3

最善の策は、思ったよりもはるかに簡単ですが、正規表現を使用してHTMLを解析しようとするのではなく、DOMがすでにテキストノードを持っており、再帰的に処理するという事実を利用することです。

これがすぐに使えるものです:

// We use this div's `innerHTML` to parse the markup of each replacment
const div = document.createElement('div');

// This is the recursive-descent function that processes all text nodes
// within the element you give it and its descendants
function doReplacement(node, rex, text) {
    // What kind of node did we get?
    switch (node.nodeType) {
        case Node.ELEMENT_NODE:
            // Probably best to leave `script` elements alone.
            // You'll probably find you want to add to this list
            // (`object`, `applet`, `style`, ...)
            if (node.nodeName.toUpperCase() !== "SCRIPT") {
                // It's an element we want to process, start with its
                // *last* child and work forward, since part of what
                // we're doing inserts into the DOM.
                let sibling;
                for (const child = node.lastChild; child; child = sibling) {
                    // Before we change this node, grab a reference to the
                    // one that precedes it
                    sibling = child.previousSibling;

                    // Recurse
                    doReplacement(child, rex, text);
                }
            }
            break;
        case Node.TEXT_NODE:
            // A text node -- let's do our replacements!
            // The first two deal with the fact that the text node
            // may have less-than symbols or ampersands in it.
            // The third, of course, does your replacement.
            div.innerHTML = node.nodeValue
                                .replace(/&/g, "&amp;")
                                .replace(/</g, "&lt;")
                                .replace(rex, text);

            // Now, the `div` has real live DOM elements for the replacement.
            // Insert them in front of this text node...
            insertChildrenBefore(div, node);
            // ...and remove the text node.
            node.parentNode.removeChild(node);
            break;
    }
}

// This function just inserts all of the children of the given container
// in front of the given reference node.
function insertChildrenBefore(container, refNode) {
    let sibling;
    const parent = refNode.parentNode;
    for (const child = container.firstChild; child; child = sibling) {
        sibling = child.nextSibling;
        parent.insertBefore(child, refNode);
    }
}

あなたはこのように呼ぶでしょう:

doReplacement(
    document.body,
    /MyName/g,
    "<span><span class='myName'>MyNameReplace</span></span>"
);

実例:

// We use this div's `innerHTML` to parse the markup of each replacment
const div = document.createElement('div');

// This is the recursive-descent function that processes all text nodes
// within the element you give it and its descendants
function doReplacement(node, rex, text) {
    // What kind of node did we get?
    switch (node.nodeType) {
        case Node.ELEMENT_NODE:
            // Probably best to leave `script` elements alone.
            // You'll probably find you want to add to this list
            // (`object`, `applet`, `style`, ...)
            if (node.nodeName.toUpperCase() !== "SCRIPT") {
                // It's an element we want to process, start with its
                // *last* child and work forward, since part of what
                // we're doing inserts into the DOM.
                let sibling;
                for (let child = node.lastChild; child; child = sibling) {
                    // Before we change this node, grab a reference to the
                    // one that precedes it
                    sibling = child.previousSibling;

                    // Recurse
                    doReplacement(child, rex, text);
                }
            }
            break;
        case Node.TEXT_NODE:
            // A text node -- let's do our replacements!
            // The first two deal with the fact that the text node
            // may have less-than symbols or ampersands in it.
            // The third, of course, does your replacement.
            div.innerHTML = node.nodeValue
                                .replace(/&/g, "&amp;")
                                .replace(/</g, "&lt;")
                                .replace(rex, text);

            // Now, the `div` has real live DOM elements for the replacement.
            // Insert them in front of this text node...
            insertChildrenBefore(div, node);
            // ...and remove the text node.
            node.parentNode.removeChild(node);
            break;
    }
}

// This function just inserts all of the children of the given container
// in front of the given reference node.
function insertChildrenBefore(container, refNode) {
    let sibling;
    const parent = refNode.parentNode;
    for (let child = container.firstChild; child; child = sibling) {
        sibling = child.nextSibling;
        parent.insertBefore(child, refNode);
    }
}

setTimeout(() => {
    doReplacement(
        document.body,
        /MyName/g,
        "<span><span class='myName'>MyNameReplace</span></span>"
    );
}, 800);
<p>MyName</p>
<p>This is MyName in a sentence.</p>
<p>This is <strong>MyName nested</strong></p>
<p>How 'bout <strong><em>making MyName nested more deeply</em></strong></p>
<p>This is MyName in an element with &lt; and &amp; in it.</p>

于 2012-12-31T18:43:45.503 に答える