Created
July 19, 2014 04:20
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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