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

IT技术 javascript jquery
2021-03-01 15:20:48

我想知道是否有一种轻量级的方法可以使用 JavaScript 或 jQuery 来嗅探文档中的特定文本字符;并找到这个字符的所有实例。接着!编写一个用$替换所有实例的能力

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

var str = 'test: '';

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

本质上; 我想要一个单页文档的解决方案。获取 X 的所有实例并将其设为 XY。只有文字字符。

6个回答

这个怎么样,替换@$

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

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

@DavidBailey 很好的捕捉,包括前后的空格让我减少了这个机会
2021-04-23 15:20:48
i如果您要替换字母字符,添加到正则表达式将为您提供不区分大小写的搜索.replace(/soMeWord/gi,"Another Word"));
2021-05-09 15:20:48

我自己的建议如下:

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小提琴演示

nativeSelector()函数来自这个问题的答案(由Anurag发布):getElementsByTagName() 等效于 textNodes

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, "$");

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

现在,这有点复杂:您需要检查三种情况:节点是否为文本节点,是否为元素及其属性应被替换,或者是否为元素及其属性应被替换。replacer对象提供用于文本节点和元件的方法。

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

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

您还会注意到此代码段使用flatMap. 如果不支持,请使用 polyfill 或将其替换为reduceconcatmapreduceconcat构造,如链接文档中所示。

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 实体

如果您需要使其与 HTML 实体一起使用,例如&shy;,上述方法将直接生成 string &shy;,因为这是一个HTML实体,并且仅在分配.innerHTML或使用相关方法时才有效

因此,让我们通过将输入字符串传递给接受 HTML 字符串的对象来解决它:一个新的临时HTMLDocument. 这是由DOMParserparseFromString方法创建的最后我们读了它documentElementtextContent

string = new DOMParser().parseFromString(string, "text/html").documentElement.textContent;

如果你想使用这个,选择上面的一种方法,这取决于你是否要替换文本之外的 HTML 属性和 DOM 属性;然后简单地用// Handle `string` — see the last section上面的行替换注释

现在您可以使用replaceOnDocument(/Güterzug/g, "G&uuml;ter&shy;zug");.

注意:如果您不使用字符串处理代码,您也可以删除{ }围绕箭头函数体。

请注意,这会解析 HTML 实体,但仍然不允许插入实际的 HTML 标签,因为我们只读取textContent. 这对于大多数情况也是安全的:由于我们正在使用parseFromString并且页面document不受影响,因此不会<script>下载也不会onerror执行处理程序。

如果结果更简单,您还应该考虑在 JavaScript 字符串\xAD&shy;直接使用而不是

@FrankConijn 尽管该解决方案使用了innerHTML具有覆盖事件侦听器问题的替换...
2021-05-01 15:20:48
Hier bin ich wieder。实际上,我真的不知道如何测试脚本的速度。我可以想象一些事情,但仅此而已。但是,我确实想出了一个简单的分叉脚本,可以替换为其他普通单词,并且可以插入 HTML 实体。参见jsfiddle.net/FrankConijn/t1e0k2fx/4将中心滚动条向右移动,缩小输出字段,然后看到“medewerkerstevredenheidsonderzoek”这个词被连字符连接起来。
2021-05-06 15:20:48
谢谢!你已经让我走上了正确的轨道,那就是innerHTML. 我正在研究另一种方法,并将两者都制作 Fiddles。所以我们可以看到哪个是下一个 Web 开发人员最快和最容易维护的。正如阿诺德常说的:我会回来的。;-)
2021-05-07 15:20:48
@FrankConijn See是否可以在innerHTML不破坏后代事件侦听器的情况下追加. 基本上,body.children[someChild].addEventListener(someEvent, someListener);然后body.innerHTML += someAdditionalContent;orbody.innerHTML = someNewContent;序列化并重新解析整个 HTML,清除任何先前绑定的事件侦听器。这就是为什么在我的方法中,我小心地替换了各个文本节点的内容。
2021-05-11 15:20:48
本身看起来很棒,但我需要用插入软连字符的相同单词替换单词。这是因为某些荷兰语单词的 CSS 连字函数出错了。然后您的函数使浏览器呈现:Lo&shy;remip&shy;sum(拉丁文示例)。你不会碰巧知道如何解决这个问题,是吗?
2021-05-15 15:20:48

我想你可能想多了。

我的方法很简单。

用 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;

与@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 $" />

优雅和高性能,这应该是公认的答案。
2021-05-14 15:20:48