// XRegExp 1.5.0 without native overrides!! var XRegExp; if (XRegExp) { throw Error("can't load XRegExp twice in the same frame"); } (function () { XRegExp = function (pattern, flags) { var output = [], currScope = XRegExp.OUTSIDE_CLASS, pos = 0, context, tokenResult, match, chr, regex; if (XRegExp.isRegExp(pattern)) { if (flags !== undefined) { throw TypeError("can't supply flags when constructing one RegExp from another"); } return clone(pattern); } if (isInsideConstructor) { throw Error("can't call the XRegExp constructor within token definition functions"); } flags = flags || ""; context = { hasNamedCapture: false, captureNames: [], hasFlag: function (flag) { return flags.indexOf(flag) > -1; }, setFlag: function (flag) { flags += flag; } }; while (pos < pattern.length) { tokenResult = runTokens(pattern, pos, currScope, context); if (tokenResult) { output.push(tokenResult.output); pos += (tokenResult.match[0].length || 1); } else { if (match = real.exec.call(nativeTokens[currScope], pattern.slice(pos))) { output.push(match[0]); pos += match[0].length; } else { chr = pattern.charAt(pos); if (chr === "[") { currScope = XRegExp.INSIDE_CLASS; } else { if (chr === "]") { currScope = XRegExp.OUTSIDE_CLASS; } } output.push(chr); pos++; } } } regex = RegExp(output.join(""), real.replace.call(flags, flagClip, "")); regex._xregexp = { source: pattern, captureNames: context.hasNamedCapture ? context.captureNames : null }; return regex; }; XRegExp.version = "1.5.0"; XRegExp.INSIDE_CLASS = 1; XRegExp.OUTSIDE_CLASS = 2; var replacementToken = /\$(?:(\d\d?|[$&`'])|{([$\w]+)})/g, flagClip = /[^gimy]+|([\s\S])(?=[\s\S]*\1)/g, quantifier = /^(?:[?*+]|{\d+(?:,\d*)?})\??/, isInsideConstructor = false, tokens = [], real = { exec: RegExp.prototype.exec, test: RegExp.prototype.test, match: String.prototype.match, replace: String.prototype.replace, split: String.prototype.split }, compliantExecNpcg = real.exec.call(/()??/, "")[1] === undefined, compliantLastIndexIncrement = function () { var x = /^/g; real.test.call(x, ""); return !x.lastIndex; } (), compliantLastIndexReset = function () { var x = /x/g; real.replace.call("x", x, ""); return !x.lastIndex; } (), hasNativeY = RegExp.prototype.sticky !== undefined, nativeTokens = {}; nativeTokens[XRegExp.INSIDE_CLASS] = /^(?:\\(?:[0-3][0-7]{0,2}|[4-7][0-7]?|x[\dA-Fa-f]{2}|u[\dA-Fa-f]{4}|c[A-Za-z]|[\s\S]))/; nativeTokens[XRegExp.OUTSIDE_CLASS] = /^(?:\\(?:0(?:[0-3][0-7]{0,2}|[4-7][0-7]?)?|[1-9]\d*|x[\dA-Fa-f]{2}|u[\dA-Fa-f]{4}|c[A-Za-z]|[\s\S])|\(\?[:=!]|[?*+]\?|{\d+(?:,\d*)?}\??)/; XRegExp.addToken = function (regex, handler, scope, trigger) { tokens.push({ pattern: clone(regex, "g" + (hasNativeY ? "y" : "")), handler: handler, scope: scope || XRegExp.OUTSIDE_CLASS, trigger: trigger || null }); }; XRegExp.cache = function (pattern, flags) { var key = pattern + "/" + (flags || ""); return XRegExp.cache[key] || (XRegExp.cache[key] = XRegExp(pattern, flags)); }; XRegExp.copyAsGlobal = function (regex) { return clone(regex, "g"); }; XRegExp.escape = function (str) { return str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); }; XRegExp.execAt = function (str, regex, pos, anchored) { regex = clone(regex, "g" + ((anchored && hasNativeY) ? "y" : "")); regex.lastIndex = pos = pos || 0; var match = regex.exec(str); if (anchored) { return (match && match.index === pos) ? match : null; } else { return match; } }; XRegExp.freezeTokens = function () { XRegExp.addToken = function () { throw Error("can't run addToken after freezeTokens"); }; }; XRegExp.isRegExp = function (o) { return Object.prototype.toString.call(o) === "[object RegExp]"; }; XRegExp.iterate = function (str, origRegex, callback, context) { var regex = clone(origRegex, "g"), i = -1, match; while (match = regex.exec(str)) { callback.call(context, match, ++i, str, regex); if (regex.lastIndex === match.index) { regex.lastIndex++; } } if (origRegex.global) { origRegex.lastIndex = 0; } }; XRegExp.matchChain = function (str, chain) { return function recurseChain(values, level) { var item = chain[level].regex ? chain[level] : { regex: chain[level] }, regex = clone(item.regex, "g"), matches = [], i; for (i = 0; i < values.length; i++) { XRegExp.iterate(values[i], regex, function (match) { matches.push(item.backref ? (match[item.backref] || "") : match[0]); }); } return ((level === chain.length - 1) || !matches.length) ? matches : recurseChain(matches, level + 1); } ([str], 0); }; RegExp.prototype.apply = function (context, args) { return this.exec(args[0]); }; RegExp.prototype.call = function (context, str) { return this.exec(str); }; function clone(regex, additionalFlags) { if (!XRegExp.isRegExp(regex)) { throw TypeError("type RegExp expected"); } var x = regex._xregexp; regex = XRegExp(regex.source, getNativeFlags(regex) + (additionalFlags || "")); if (x) { regex._xregexp = { source: x.source, captureNames: x.captureNames ? x.captureNames.slice(0) : null }; } return regex; } function getNativeFlags(regex) { return (regex.global ? "g" : "") + (regex.ignoreCase ? "i" : "") + (regex.multiline ? "m" : "") + (regex.extended ? "x" : "") + (regex.sticky ? "y" : ""); } function runTokens(pattern, index, scope, context) { var i = tokens.length, result, match, t; isInsideConstructor = true; try { while (i--) { t = tokens[i]; if ((scope & t.scope) && (!t.trigger || t.trigger.call(context))) { t.pattern.lastIndex = index; match = t.pattern.exec(pattern); if (match && match.index === index) { result = { output: t.handler.call(context, match, scope), match: match }; break; } } } } catch (err) { throw err; } finally { isInsideConstructor = false; } return result; } function indexOf(array, item, from) { if (Array.prototype.indexOf) { return array.indexOf(item, from); } for (var i = from || 0; i < array.length; i++) { if (array[i] === item) { return i; } } return -1; } XRegExp.addToken(/\(\?#[^)]*\)/, function (match) { return real.test.call(quantifier, match.input.slice(match.index + match[0].length)) ? "" : "(?:)"; }); XRegExp.addToken(/\((?!\?)/, function () { this.captureNames.push(null); return "("; }); XRegExp.addToken(/\(\?<([$\w]+)>/, function (match) { this.captureNames.push(match[1]); this.hasNamedCapture = true; return "("; }); XRegExp.addToken(/\\k<([\w$]+)>/, function (match) { var index = indexOf(this.captureNames, match[1]); return index > -1 ? "\\" + (index + 1) + (isNaN(match.input.charAt(match.index + match[0].length)) ? "" : "(?:)") : match[0]; }); XRegExp.addToken(/\[\^?]/, function (match) { return match[0] === "[]" ? "\\b\\B" : "[\\s\\S]"; }); XRegExp.addToken(/^\(\?([imsx]+)\)/, function (match) { this.setFlag(match[1]); return ""; }); XRegExp.addToken(/(?:\s+|#.*)+/, function (match) { return real.test.call(quantifier, match.input.slice(match.index + match[0].length)) ? "" : "(?:)"; }, XRegExp.OUTSIDE_CLASS, function () { return this.hasFlag("x"); }); XRegExp.addToken(/\./, function () { return "[\\s\\S]"; }, XRegExp.OUTSIDE_CLASS, function () { return this.hasFlag("s"); }); })();