Skip to content

Instantly share code, notes, and snippets.

@jarrodhroberson
Created November 16, 2017 00:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jarrodhroberson/ccbcac5d149a571edad9ca4d132b85e0 to your computer and use it in GitHub Desktop.
Save jarrodhroberson/ccbcac5d149a571edad9ca4d132b85e0 to your computer and use it in GitHub Desktop.
String.prototype.format
String.prototype.format = function() {
var self = this,
formats = self.match(/{(:?\d*)}/g), // an array of formats `{}` found in the string
counter = 0, // A counter to keep track of what index to replace with
args = arguments; // Dereferencing arguments for use in the nested code blocks
if (formats) {
formats.forEach(function(format) { // We loop through each format expression in the array
var namedMatch = format.match(/{:(\d+)}/), // Checking if the format is a named replacement (i.e. {:1})
reg;
if (namedMatch) { // If it is a named match, we replace all instances of that in one go.
reg = new RegExp(format, 'g');
if (self.match(reg)) { // If the named match wasn't replaced yet, we replace it
self = self.replace(reg, args[namedMatch[1]]); // Make the replacement
/**
* The counter is used to make sure we're always replacing in the right order.
* String.format() will replace all non-named replacements `{}` with
* the first unused string replacement in args.
*
* Example:
* ```
* "Hello {}! My name is {:1}. I love {}, because I am {:1}. I also like {}. See you later -{:1}"
* .format('world', 'Kyle', 'candy', 'jazz');
* ```
*
* Flow:
* (counter = 0)
* First {} -> 'world' ( counter = 1 )
* All {:1} -> 'Kyle' ( counter = 2 )
* Second {} -> 'candy' ( counter = 3 )
* Second {:1} -> not replaced ( counter = 3 )
* Final {} -> 'jazz' ( counter = 4 )
* -------------------------------------------
* Output: "Hello world! My name is Kyle. I love candy, because I am Kyle. I also like jazz. See you later -Kyle"
*
* As you can see, we maintained the order of replacements for non-named values,
* while still replacing with named values
*/
counter+= counter > namedMatch[1] ? 0 : 1;
}
} else {
reg = new RegExp(format); // If it's not a named replacement...
self = self.replace(reg, args[counter]); // replace it with the next replacement in line
counter+= 1;
}
});
}
return self; // return the completed string (this)
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment