使用JS查找并替换文档中的特定文本字符

时间:2013-09-05 18:48:55

标签: javascript jquery

我想知道是否有一种轻量级的方式我可以使用JavaScript或jQuery来嗅出文档中的特定文本字符;说并查找此角色的所有实例。 然后!使用 $ 编写替换所有实例的功能。

我为初学者找到了这个片段:

var str = 'test: '';

str = str.replace(/'/g, "'");

本质;我想要一个单页文档的解决方案。抓住X的所有实例并使其成为XY。只有文字字符。

14 个答案:

答案 0 :(得分:24)

如何做到这一点,将@替换为$

$("body").children().each(function () {
    $(this).html( $(this).html().replace(/@/g,"$") );
});

http://jsfiddle.net/maximua/jp96C/1/

答案 1 :(得分:20)

我自己的建议如下:

function nativeSelector() {
    var elements = document.querySelectorAll("body, body *");
    var results = [];
    var child;
    for(var i = 0; i < elements.length; i++) {
        child = elements[i].childNodes[0];
        if(elements[i].hasChildNodes() && child.nodeType == 3) {
            results.push(child);
        }
    }
    return results;
}

var textnodes = nativeSelector(),
    _nv;
for (var i = 0, len = textnodes.length; i<len; i++){
    _nv = textnodes[i].nodeValue;
    textnodes[i].nodeValue = _nv.replace(/£/g,'€');
}

JS Fiddle demo

nativeSelector()功能来自an answer(由Anurag发布)此问题:getElementsByTagName() equivalent for textNodes

答案 2 :(得分:11)

ECMAScript 2015+方法

解决此任务时的陷阱

这似乎是一件容易的事,但你必须要处理好几件事:

  • 简单地替换整个HTML会杀死所有DOM功能,例如事件侦听器
  • 替换HTML也可能会替换<script><style>内容,或HTML标记或属性,这并不总是需要
  • 更改HTML可能会导致攻击
  • 您可能还希望替换titlealt等属性(以受控方式)

使用以下方法通常无法解决防范攻击的问题。例如。如果fetch调用从页面某处读取URL,然后向该URL发送请求,则下面的函数不会停止,因为这种情况本质上是不安全的。

替换所有元素的文本内容

这基本上选择了包含普通文本的所有元素,遍历它们的子节点 - 其中也包括文本节点 - ,寻找那些文本节点并替换它们的内容。

您可以选择指定其他根target,例如replaceOnDocument(/€/g, "$", { target: someElement });;默认情况下,会选择<body>

const replaceOnDocument = (pattern, string, {target = document.body} = {}) => {
  // Handle `string` — see the last section
  [
    target,
    ...target.querySelectorAll("*:not(script):not(noscript):not(style)")
  ].forEach(({childNodes: [...nodes]}) => nodes
    .filter(({nodeType}) => nodeType === document.TEXT_NODE)
    .forEach((textNode) => textNode.textContent = textNode.textContent.replace(pattern, string)));
};

replaceOnDocument(/€/g, "$");

替换文本节点,元素属性和属性

现在,这有点复杂:你需要检查三种情况:节点是否是 text 节点,它是否是一个元素,它的属性应该是替换,或者它是否是一个元素,它的属性应该被替换。 replacer对象为文本节点和元素提供方法。

在替换属性和属性之前,replacer需要检查元素是否具有匹配的属性;否则会产生新的属性。它还需要检查目标属性是否是字符串,因为只能替换字符串,或者目标属性的匹配属性是否不是函数,因为这可能会导致攻击。

在下面的示例中,您可以看到如何使用扩展功能:在可选的第三个参数中,您可以添加attrs属性和props属性,这是一个可迭代的(例如, array)每个,分别用于要替换的属性和要替换的属性。

您还会注意到此代码段使用flatMap。如果不支持,请使用填充或使用reduce - concatmap - reduce - concat构造替换它,如链接中所示文档。

const replaceOnDocument = (() => {
    const replacer = {
      [document.TEXT_NODE](node, pattern, string){
        node.textContent = node.textContent.replace(pattern, string);
      },
      [document.ELEMENT_NODE](node, pattern, string, {attrs, props} = {}){
        attrs.forEach((attr) => {
          if(typeof node[attr] !== "function" && node.hasAttribute(attr)){
            node.setAttribute(attr, node.getAttribute(attr).replace(pattern, string));
          }
        });
        props.forEach((prop) => {
          if(typeof node[prop] === "string" && node.hasAttribute(prop)){
            node[prop] = node[prop].replace(pattern, string);
          }
        });
      }
    };

    return (pattern, string, {target = document.body, attrs: [...attrs] = [], props: [...props] = []} = {}) => {
      // Handle `string` — see the last section
      [
        target,
        ...[
          target,
          ...target.querySelectorAll("*:not(script):not(noscript):not(style)")
        ].flatMap(({childNodes: [...nodes]}) => nodes)
      ].filter(({nodeType}) => replacer.hasOwnProperty(nodeType))
        .forEach((node) => replacer[node.nodeType](node, pattern, string, {
          attrs,
          props
        }));
    };
})();

replaceOnDocument(/€/g, "$", {
  attrs: [
    "title",
    "alt",
    "onerror" // This will be ignored
  ],
  props: [
    "value" // Changing an `<input>`’s `value` attribute won’t change its current value, so the property needs to be accessed here
  ]
});

替换为HTML实体

如果您需要使用&shy;之类的HTML实体,上述方法只会生成字符串&shy;,因为它是 HTML 实体,并且只会在分配.innerHTML或使用相关方法时工作。

所以让我们通过将输入字符串传递给接受HTML字符串的东西来解决它:一个新的,临时的HTMLDocument。这是由DOMParser的{​​{1}}方法创建的;最后,我们阅读了parseFromString的{​​{1}}:

documentElement

如果要使用此方法,请选择上述方法之一,具体取决于您是否要替换除文本之外的HTML属性和DOM属性;然后只需用上面的行替换评论textContent

现在您可以使用string = new DOMParser().parseFromString(string, "text/html").documentElement.textContent;

注意:如果您不使用字符串处理代码,您也可以删除箭头函数体周围的// Handle `string` — see the last section replaceOnDocument(/Güterzug/g, "G&uuml;ter&shy;zug");

请注意,这会解析HTML实体,但仍然不允许插入实际的HTML标记,因为我们只读取{。对于的大多数情况,这也是安全的:因为我们正在使用parseFromString并且页面的}不受影响,所以不会下载textContent而不会{{1}处理程序被执行。

如果结果更简单,您还应该考虑直接在JavaScript字符串中使用document代替<script>

答案 3 :(得分:2)

在javascript中不使用jquery:

document.body.innerText = document.body.innerText.replace('actualword', 'replacementword');

答案 4 :(得分:1)

对于文档body中的每个元素,使用 .text(fn) 函数修改其文本。

$("body *").text(function() {
    return $(this).text().replace("x", "xy");
});

答案 5 :(得分:1)

最好是在服务器端执行此操作或将货币符号包装在您可以选择的元素中,然后再将其返回到浏览器,但如果两者都不是选项,则可以选择正文中的所有文本节点并执行替换他们。下面我使用我2年前写的插件,这是为了突出显示文本。我正在做的是找到所有出现的€并用类货币符号包裹它,然后我将替换这些跨度的文本。

<强> Demo

(function($){

    $.fn.highlightText = function () {
        // handler first parameter
        // is the first parameter a regexp?
        var re,
            hClass,
            reStr,
            argType = $.type(arguments[0]),
            defaultTagName = $.fn.highlightText.defaultTagName;

        if ( argType === "regexp" ) {
            // first argument is a regular expression
            re = arguments[0];
        }       
        // is the first parameter an array?
        else if ( argType === "array" ) {
            // first argument is an array, generate
            // regular expression string for later use
            reStr = arguments[0].join("|");
        }       
        // is the first parameter a string?
        else if ( argType === "string" ) {
            // store string in regular expression string
            // for later use
            reStr = arguments[0];
        }       
        // else, return out and do nothing because this
        // argument is required.
        else {
            return;
        }

        // the second parameter is optional, however,
        // it must be a string or boolean value. If it is 
        // a string, it will be used as the highlight class.
        // If it is a boolean value and equal to true, it 
        // will be used as the third parameter and the highlight
        // class will default to "highlight". If it is undefined,
        // the highlight class will default to "highlight" and 
        // the third parameter will default to false, allowing
        // the plugin to match partial matches.
        // ** The exception is if the first parameter is a regular
        // expression, the third parameter will be ignored.
        argType = $.type(arguments[1]);
        if ( argType === "string" ) {
            hClass = arguments[1];
        }
        else if ( argType === "boolean" ) {
            hClass = "highlight";
            if ( reStr ) {
                reStr = "\\b" + reStr + "\\b";
            }
        }
        else {
            hClass = "highlight";
        }

        if ( arguments[2] && reStr ) {
            reStr = reStr = "\\b" + reStr + "\\b";
        } 

        // if re is not defined ( which means either an array or
        // string was passed as the first parameter ) create the
        // regular expression.
        if (!re) {
            re = new RegExp( "(" + reStr + ")", "ig" );
        }

        // iterate through each matched element
        return this.each( function() {
            // select all contents of this element
            $( this ).find( "*" ).andSelf().contents()

            // filter to only text nodes that aren't already highlighted
            .filter( function () {
                return this.nodeType === 3 && $( this ).closest( "." + hClass ).length === 0;
            })

            // loop through each text node
            .each( function () {
                var output;
                output = this.nodeValue
                    .replace( re, "<" + defaultTagName + " class='" + hClass + "'>$1</" + defaultTagName +">" );
                if ( output !== this.nodeValue ) {
                    $( this ).wrap( "<p></p>" ).parent()
                        .html( output ).contents().unwrap();
                }
            });
        });
    };

    $.fn.highlightText.defaultTagName = "span";

})( jQuery );

$("body").highlightText("€","currency-symbol");
$("span.currency-symbol").text("$");

答案 6 :(得分:1)

使用拆分和连接方法

$("#idBut").click(function() {
    $("body").children().each(function() {
        $(this).html($(this).html().split('@').join("$"));
    });
});

这里是solution

答案 7 :(得分:1)

与@ max-malik的答案类似,但不使用jQuery,您也可以使用document.createTreeWalker执行此操作:

button.addEventListener('click', e => {
  const treeWalker = document.createTreeWalker(document.body);
  while (treeWalker.nextNode()) {
    const node = treeWalker.currentNode;
    node.textContent = node.textContent.replace(/@/g, '$');
  }
})
<div>This is an @ that we are @ replacing.</div>
<div>This is another @ that we are replacing.</div>
<div>
  <span>This is an @ in a span in @ div.</span>
</div>
<br>
<input id="button" type="button" value="Replace @ with $" />

答案 8 :(得分:1)

Vanilla JavaScript解决方案:

document.body.innerHTML = document.body.innerHTML.replace(/Original/g, "New")

答案 9 :(得分:0)

您可以使用:

str.replace(/text/g, "replaced text");

答案 10 :(得分:0)

str.replace(/replacetext/g,'actualtext')

这会将replacetext的所有实例替换为actualtext

答案 11 :(得分:0)

无论如何,当你正在使用jQuery时,请尝试:

https://github.com/cowboy/jquery-replacetext

然后就这样做

a <- c("Tampa Bay Buccaneers / 1st / 1st pick / 2015", "Tennessee Titans / 1st / 2nd pick / 2015", 
"Oakland Raiders / 1st / 4th pick / 2015", "Washington Redskins / 1st / 5th pick / 2015", 
"New York Jets / 1st / 6th pick / 2015")

似乎只能替换文本而不是弄乱其他元素

答案 12 :(得分:0)

我认为您可能对此有过多的想法。

我的方法很简单。

使用div标签将页面括起来:

<div id="mydiv">
<!-- you page here -->
</div>

在您的JavaScript中:

var html=document.getElementById('mydiv').innerHTML;
html = html.replace(/this/g,"that");
document.getElementById('mydiv').innerHTML=html;

答案 13 :(得分:0)

这可能会帮助某些人寻找此答案: 下面使用jquery搜索整个文档,仅替换文本。 例如,如果我们有

<a href="/i-am/123/a/overpopulation">overpopulation</a>

我们想在“人口过剩”一词周围添加一个类别为“人口过剩”的跨度

<a href="/i-am/123/a/overpopulation"><span class="overpop">overpopulation</span></a>

我们将运行以下

        $("*:containsIN('overpopulation')").filter(
            function() {
                return $(this).find("*:contains('" + str + "')").length == 0
            }
        ).html(function(_, html) {
            if (html != 'undefined') {
                return html.replace(/(overpopulation)/gi, '<span class="overpop">$1</span>');
            }

        });

搜索不区分大小写,搜索整个文档,仅替换文本部分,在这种情况下,我们正在搜索字符串“ overpopulation”

    $.extend($.expr[":"], {
        "containsIN": function(elem, i, match, array) {
            return (elem.textContent || elem.innerText || "").toLowerCase().indexOf((match[3] || "").toLowerCase()) >= 0;
        }
    });