Skip to content

Instantly share code, notes, and snippets.

@mrcoles
Last active February 25, 2022 05:41
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save mrcoles/76b79473be0572e79434c2b579f0e16a to your computer and use it in GitHub Desktop.
Save mrcoles/76b79473be0572e79434c2b579f0e16a to your computer and use it in GitHub Desktop.
Replace all instances of one word with another in a web page
// ### Replace words in document
//
// Update all instances of `fromWord` to `toWord` within the text
// in the current document.
//
function replaceWordsInDocument(fromWord, toWord) {
if (/\s/.test(fromWord)) {
throw new Error('You must enter a single word without whitespace');
}
const textNodes = iterAllTextNodes();
replaceInNodes(fromWord, toWord, textNodes);
}
// ### Iterate all text nodes
//
// Returns a generator that yields all the text nodes within a
// document (excluding those within link, style, and script tags)
//
function* iterAllTextNodes() {
const ignoreNodes = new Set(['LINK', 'STYLE', 'SCRIPT']);
for (const elt of document.querySelectorAll('*')) {
if (!ignoreNodes.has(elt.nodeName)) {
for (const node of elt.childNodes) {
if (node.nodeType === 3) {
yield node;
}
}
}
}
}
// ### Replace in nodes
//
// Replaces all instances of fromText with toText within
// the textNodes. Matches whole words and expects
// `fromText` to have no whitespaces. Matches are also
// case-insensitve, and replacements attempt to replicate
// the original capitalization found in the node.
//
// - fromText (string) representing one word with no spaces
// - toText (string)
// - textNodes (nodeList of text nodes)
//
function replaceInNodes(fromText, toText, textNodes) {
const fromLower = fromText.toLowerCase();
const replacements = {
[fromLower]: toText.toLowerCase(),
[fromText.toUpperCase()]: toText.toUpperCase(),
[capitalize(fromText)]: capitalize(toText)
}
for (const node of textNodes) {
const newText = node.nodeValue.split(/(\s+)/).map((token, i) => {
if (i % 2 === 0) {
const tokenLower = token.toLowerCase();
if (tokenLower === fromLower) {
return replacements[token] || toText;
}
}
return token;
}).join('');
// looks faster to only set if changed https://jsperf.com/node-nodevalue
if (newText !== node.nodeValue) {
node.nodeValue = newText;
}
}
}
// ### Helpers
//
const capitalize = (text) => text.substring(0, 1).toUpperCase() + text.toLowerCase().substring(1);
// ### Run it
//
replaceWordsInDocument('you', 'y\'all');
@mrcoles
Copy link
Author

mrcoles commented Dec 14, 2017

This uses some es6 features like generators, arrow functions, and computed property keys, which may not work in some older browsers.

Usage:

replaceWordsInDocument('you', 'y\'all');

😉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment