When I was writing my linear-gradient() to -webkit-gradient() converter, I knew in advance that I would have to use a quite large regular expression to validate and parse the input. Such a regex would be incredibly hard to read and fix potential issues, so I tried to find a way to cut the process down in reusable parts.
Turns out JavaScript regular expression objects have a .source property that can be used in the RegExp constructor to create a new RegExp out of another one. So I wrote a new function that takes a string with identifiers for regexp replacements in and replaces them with the corresponding sub-regexps, taken from an object literal as a second argument:
/** * Create complex regexps in an easy to read way * @param str {String} Final regex with for replacements * @param replacements {Object} Object with the replacements * @param flags {String} Just like the flags argument in the RegExp constructor */ RegExp.create = function(str, replacements, flags) { for(var id in replacements) { var replacement = replacements[id], idRegExp = RegExp(β + id + ', βgiβ);
if(replacement.source) { replacement = replacement.source.replace(/^\^|\$$/g, ββ); }
// Donβt add extra parentheses if they already exist str = str.replace(RegExp(β\\(β + idRegExp.source + β\\)β, βgiβ), β(β + replacement + β)β);
str = str.replace(idRegExp, β(?:β + replacement + β)β); }
return RegExp(str, flags); };
If you donβt like adding a function to the RegExp object, you can name it however you want. Hereβs how I used it for my linear-gradient() parser:
self.regex = {};
self.regex.number = /^-?[0-9]*\.?[0-9]+
self.regex.direction = RegExp.create(β^(?:|deg|0)$β, { keyword: self.regex.keyword, number: self.regex.number });
self.regex.color = RegExp.create(β(?:||)β, {
keyword: /^(?:red|tan|grey|gray|lime|navy|blue|teal|aqua|cyan|gold|peru|pink|plum|snow|[a-z]{5,20})
self.regex.percentage = RegExp.create(β^(?:%|0)$β, { number: self.regex.number });
self.regex.length = RegExp.create(β|0β, { number: self.regex.number, unit: /%|px|mm|cm|in|em|rem|en|ex|ch|vm|vw|vh/ });
self.regex.colorStop = RegExp.create(β\\s*?β, { color: self.regex.color, length: self.regex.length }, βgβ);
self.regex.linearGradient = RegExp.create(β^linear-gradient\\(\\s*(?:()\\s*,)?\\s*(\\s*(?:,\\s*\\s*)+)\\)$β, { direction: self.regex.direction, colorStop: self.regex.colorStop }, βiβ);
(self in this case was a local variable, not the window object)