Skip to content

Instantly share code, notes, and snippets.

@gordonbrander
Created July 19, 2014 04:20
Show Gist options
  • Save gordonbrander/f5f276c177b801a1628b to your computer and use it in GitHub Desktop.
Save gordonbrander/f5f276c177b801a1628b to your computer and use it in GitHub Desktop.
searchAndReplace(string, pattern, step): step through RegExp matches and generate replacements with callback that has full access to string indexes.
// Splice in a string between `begin` and `end` indexes.
// Returns a new string.
function spliceString(string, insert, begin, end) {
return string.slice(0, begin) + insert + string.slice(end);
}
// Search a string with a regular expression, where `step` callback will
// be called at each match, allowing you to perform extra logic and create a
// replacement string.
//
// Abstracts away all the scary janky footguns of `RegExp.exec`.
//
// See http://alexyoung.org/2011/08/01/lightweight-markup/
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/exec
function searchAndReplace(string, pattern, step) {
// Clone RegExp/pattern string. We're going to mutate its state.
var re = new RegExp(pattern);
// Initialize variables we'll use in the loop.
var match, replacement, diff, substring, startIndex, endIndex;
while ((match = re.exec(string)) !== null) {
// Calculate match start index. `lastIndex` contains the index to start
// next search on, so we actually want to back up by the `length` of the
// matched substring.
substring = match[0];
startIndex = match.index;
endIndex = startIndex + substring.length;
// Create replacement string given the environmental variables.
replacement = step(substring, string, startIndex);
// Splice replacement string into place of old substring.
string = spliceString(string, replacement, startIndex, endIndex);
// Calculate the difference in length between the substring and
// its replacement.
diff = replacement.length - substring.length;
// We changed the width of the string, so we have to adjust the `lastIndex`
// property so the `RegExp` object stays in sync.
re.lastIndex = re.lastIndex + diff;
}
return string;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment