使用JS查找并替换文档中的特定文本字符
我想知道是否有一种轻量级的方式我可以使用JavaScript或jQuery来嗅出文档中的特定文本字符; 说€并找到这个角色的所有实例。 然后! 写一个用$替换所有实例的能力。
我找到了这个首发代码片段:
var str = 'test: ''; str = str.replace(/'/g, "'");
实质上; 我想要一个单页文档的解决方案。 抓住X的所有实例并使其成为XY。 只有文字字符。
怎么样,用$
替换@
:
$("body").children().each(function () { $(this).html( $(this).html().replace(/@/g,"$") ); });
我个人的建议如下:
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
JS小提琴演示 。
nativeSelector()
函数来自一个答案 (由Anurag发布)到这个问题: getElementsByTagName()等效于textNodes 。
ECMAScript 2015+方法
解决此任务时的陷阱
这似乎是一件容易的事,但你必须要处理好几件事:
- 简单地替换整个HTML会杀死所有DOMfunction,例如事件侦听器
- 替换HTML也可以替换
或
内容,或HTML标记或属性,这并不总是需要的
- 更改HTML可能会导致xss攻击
- 您可能还想替换
title
和alt
等属性(以受控方式)
通常使用以下方法无法解决防御xss攻击的问题。 例如,如果fetch
调用从页面上的某个位置读取URL,然后向该URL发送请求,则下面的function将不会停止,因为此方案本质上是不安全的。
替换所有元素的文本内容
这基本上选择包含普通文本的所有元素,遍历它们的子节点 - 其中也包括文本节点 - ,寻找那些文本节点并替换它们的内容。
您可以选择指定不同的根target
,例如replaceOnDocument(/€/g, "$", { target: someElement });
; 默认情况下,选择 。
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
对象为文本节点和元素提供方法。
在替换属性和属性之前,替换者需要检查元素是否具有匹配的属性; 否则会产生新的属性。 它还需要检查目标属性是否是字符串,因为只能替换字符串,或者目标属性的匹配属性是否不是函数,因为这可能导致xss攻击。
在下面的示例中,您可以看到如何使用扩展function:在可选的第三个参数中,您可以添加一个attrs
属性和一个props
属性,它们是一个可迭代的(例如一个数组),用于要替换的属性和要分别替换的属性。
您还会注意到此代码段使用的是flatMap
。 如果不支持,请使用polyfill或用reduce
- concat
或map
- 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 ``'s `value` attribute won't change its current value, so the property needs to be accessed here ] });
替换为HTML实体
如果你需要使用HTML实体,比如
,上面的方法只会字面上产生字符串
,因为那是一个HTML实体,只有在分配.innerHTML
或使用相关方法时才有效。
因此,让我们通过将输入字符串传递给接受HTML字符串的东西来解决它:一个新的临时HTMLDocument
。 这是由DOMParser
的parseFromString
方法创建的; 最后我们读了它的documentElement
的textContent
:
string = new DOMParser().parseFromString(string, "text/html").documentElement.textContent;
如果要使用此方法,请选择上述方法之一,具体取决于您是否要替换除文本之外的HTML属性和DOM属性; 然后简单地替换注释// Handle `string` — see the last section
一行// Handle `string` — see the last section
。
现在你可以使用replaceOnDocument(/Güterzug/g, "Güterzug");
。
注意:如果您不使用字符串处理代码,您也可以删除箭头函数体周围的{
}
。
请注意,这会解析HTML实体,但仍然不允许插入实际的HTML标记,因为我们只读取textContent
。 这对于xss的大多数情况也是安全的:因为我们使用parseFromString
并且页面的document
不受影响,所以不会下载并且不会执行任何error handling程序。
您还应该考虑使用\xAD
而不是
直接在你的JavaScript字符串中,如果它变得更简单。
在javascript中不使用jquery
document.body.innerText.replace('actualword', 'replacementword');
对于文档body
每个元素,使用.text(fn)函数修改其文本。
$("body *").text(function() { return $(this).text().replace("x", "xy"); });
最好的方法是在服务器端执行此操作或将货币符号包装在您可以选择的元素中,然后再将其返回到浏览器,但如果两者都不是选项,则可以选择正文中的所有文本节点并对其进行替换。 下面我使用我2年前写的插件,这是为了突出显示文本。 我正在做的是找到所有出现的€并用类货币符号包裹它,然后我将替换这些跨度的文本。
演示
(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( "" ).parent() .html( output ).contents().unwrap(); } }); }); }; $.fn.highlightText.defaultTagName = "span"; })( jQuery ); $("body").highlightText("€","currency-symbol"); $("span.currency-symbol").text("$");
使用拆分和连接方法
$("#idBut").click(function() { $("body").children().each(function() { $(this).html($(this).html().split('@').join("$")); }); });
这是解决方案
str.replace(/replacetext/g,'actualtext')
这将替换actualtext
所有实例与actualtext
您可以使用:
str.replace(/text/g, "replaced text");
正如您将使用jQuery一样,请尝试:
https://github.com/cowboy/jquery-replacetext
然后就做
$("p").replaceText("£", "$")
它似乎很好地只替换文本而不是弄乱其他元素
与@ 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, '$'); } })
This is an @ that we are @ replacing. This is another @ that we are replacing. This is an @ in a span in @ div.