Skip to content

Commit

Permalink
Updating to XRegExp.js version 1.5.1 as per discussion in SyntaxHighl…
Browse files Browse the repository at this point in the history
  • Loading branch information
ianneub committed Feb 27, 2012
1 parent b7154ce commit d871c84
Showing 1 changed file with 87 additions and 75 deletions.
162 changes: 87 additions & 75 deletions scripts/XRegExp.js
@@ -1,5 +1,5 @@
// XRegExp 1.5.0
// (c) 2007-2010 Steven Levithan
// XRegExp 1.5.1
// (c) 2007-2012 Steven Levithan
// MIT License
// <http://xregexp.com>
// Provides an augmented, extensible, cross-browser implementation of regular expressions,
Expand All @@ -13,15 +13,16 @@ if (XRegExp) {
}

// Run within an anonymous function to protect variables and avoid new globals
(function () {
(function (undefined) {

//---------------------------------
// Constructor
//---------------------------------

// Accepts a pattern and flags; returns a new, extended `RegExp` object. Differs from a native
// regular expression in that additional syntax and flags are supported and cross-browser
// syntax inconsistencies are ameliorated
// syntax inconsistencies are ameliorated. `XRegExp(/regex/)` clones an existing regex and
// converts to type XRegExp
XRegExp = function (pattern, flags) {
var output = [],
currScope = XRegExp.OUTSIDE_CLASS,
Expand Down Expand Up @@ -56,7 +57,7 @@ if (XRegExp) {
} else {
// Check for native multicharacter metasequences (excluding character classes) at
// the current position
if (match = real.exec.call(nativeTokens[currScope], pattern.slice(pos))) {
if (match = nativ.exec.call(nativeTokens[currScope], pattern.slice(pos))) {
output.push(match[0]);
pos += match[0].length;
} else {
Expand All @@ -72,7 +73,7 @@ if (XRegExp) {
}
}

regex = RegExp(output.join(""), real.replace.call(flags, flagClip, ""));
regex = RegExp(output.join(""), nativ.replace.call(flags, flagClip, ""));
regex._xregexp = {
source: pattern,
captureNames: context.hasNamedCapture ? context.captureNames : null
Expand All @@ -85,7 +86,7 @@ if (XRegExp) {
// Public properties
//---------------------------------

XRegExp.version = "1.5.0";
XRegExp.version = "1.5.1";

// Token scope bitflags
XRegExp.INSIDE_CLASS = 1;
Expand All @@ -102,22 +103,17 @@ if (XRegExp) {
isInsideConstructor = false,
tokens = [],
// Copy native globals for reference ("native" is an ES3 reserved keyword)
real = {
nativ = {
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, // check `exec` handling of nonparticipating capturing groups
compliantExecNpcg = nativ.exec.call(/()??/, "")[1] === undefined, // check `exec` handling of nonparticipating capturing groups
compliantLastIndexIncrement = function () {
var x = /^/g;
real.test.call(x, "");
return !x.lastIndex;
}(),
compliantLastIndexReset = function () {
var x = /x/g;
real.replace.call("x", x, "");
nativ.test.call(x, "");
return !x.lastIndex;
}(),
hasNativeY = RegExp.prototype.sticky !== undefined,
Expand Down Expand Up @@ -172,15 +168,17 @@ if (XRegExp) {
// Accepts a string to search, regex to search with, position to start the search within the
// string (default: 0), and an optional Boolean indicating whether matches must start at-or-
// after the position or at the specified position only. This function ignores the `lastIndex`
// property of the provided regex
// of the provided regex in its own handling, but updates the property for compatibility
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;
var r2 = clone(regex, "g" + ((anchored && hasNativeY) ? "y" : "")),
match;
r2.lastIndex = pos = pos || 0;
match = r2.exec(str); // Run the altered `exec` (required for `lastIndex` fix, etc.)
if (anchored && match && match.index !== pos)
match = null;
if (regex.global)
regex.lastIndex = match ? r2.lastIndex : 0;
return match;
};

// Breaks the unrestorable link to XRegExp's private list of tokens, thereby preventing
Expand All @@ -202,16 +200,18 @@ if (XRegExp) {
// Executes `callback` once per match within `str`. Provides a simpler and cleaner way to
// iterate over regex matches compared to the traditional approaches of subverting
// `String.prototype.replace` or repeatedly calling `exec` within a `while` loop
XRegExp.iterate = function (str, origRegex, callback, context) {
var regex = clone(origRegex, "g"),
XRegExp.iterate = function (str, regex, callback, context) {
var r2 = clone(regex, "g"),
i = -1, match;
while (match = regex.exec(str)) {
while (match = r2.exec(str)) { // Run the altered `exec` (required for `lastIndex` fix, etc.)
if (regex.global)
regex.lastIndex = r2.lastIndex; // Doing this to follow expectations if `lastIndex` is checked within `callback`
callback.call(context, match, ++i, str, regex);
if (regex.lastIndex === match.index)
regex.lastIndex++;
if (r2.lastIndex === match.index)
r2.lastIndex++;
}
if (origRegex.global)
origRegex.lastIndex = 0;
if (regex.global)
regex.lastIndex = 0;
};

// Accepts a string and an array of regexes; returns the result of using each successive regex
Expand Down Expand Up @@ -268,16 +268,18 @@ if (XRegExp) {
// rather than the empty string.
// - `lastIndex` should not be incremented after zero-length matches.
RegExp.prototype.exec = function (str) {
var match = real.exec.apply(this, arguments),
name, r2;
var match, name, r2, origLastIndex;
if (!this.global)
origLastIndex = this.lastIndex;
match = nativ.exec.apply(this, arguments);
if (match) {
// Fix browsers whose `exec` methods don't consistently return `undefined` for
// nonparticipating capturing groups
if (!compliantExecNpcg && match.length > 1 && indexOf(match, "") > -1) {
r2 = RegExp(this.source, real.replace.call(getNativeFlags(this), "g", ""));
r2 = RegExp(this.source, nativ.replace.call(getNativeFlags(this), "g", ""));
// Using `str.slice(match.index)` rather than `match[0]` in case lookahead allowed
// matching due to characters outside the match
real.replace.call(str.toString().slice(match.index), r2, function () {
nativ.replace.call((str + "").slice(match.index), r2, function () {
for (var i = 1; i < arguments.length - 2; i++) {
if (arguments[i] === undefined)
match[i] = undefined;
Expand All @@ -296,29 +298,33 @@ if (XRegExp) {
if (!compliantLastIndexIncrement && this.global && !match[0].length && (this.lastIndex > match.index))
this.lastIndex--;
}
if (!this.global)
this.lastIndex = origLastIndex; // Fix IE, Opera bug (last tested IE 9.0.5, Opera 11.61 on Windows)
return match;
};

// Don't override `test` if it won't change anything
if (!compliantLastIndexIncrement) {
// Fix browser bug in native method
RegExp.prototype.test = function (str) {
// Use the native `exec` to skip some processing overhead, even though the overriden
// `exec` would take care of the `lastIndex` fix
var match = real.exec.call(this, str);
// Fix browsers that increment `lastIndex` after zero-length matches
if (match && this.global && !match[0].length && (this.lastIndex > match.index))
this.lastIndex--;
return !!match;
};
}
// Fix browser bugs in native method
RegExp.prototype.test = function (str) {
// Use the native `exec` to skip some processing overhead, even though the altered
// `exec` would take care of the `lastIndex` fixes
var match, origLastIndex;
if (!this.global)
origLastIndex = this.lastIndex;
match = nativ.exec.call(this, str);
// Fix browsers that increment `lastIndex` after zero-length matches
if (match && !compliantLastIndexIncrement && this.global && !match[0].length && (this.lastIndex > match.index))
this.lastIndex--;
if (!this.global)
this.lastIndex = origLastIndex; // Fix IE, Opera bug (last tested IE 9.0.5, Opera 11.61 on Windows)
return !!match;
};

// Adds named capture support and fixes browser bugs in native method
String.prototype.match = function (regex) {
if (!XRegExp.isRegExp(regex))
regex = RegExp(regex); // Native `RegExp`
if (regex.global) {
var result = real.match.apply(this, arguments);
var result = nativ.match.apply(this, arguments);
regex.lastIndex = 0; // Fix IE bug
return result;
}
Expand All @@ -333,20 +339,24 @@ if (XRegExp) {
// third (`flags`) parameter
String.prototype.replace = function (search, replacement) {
var isRegex = XRegExp.isRegExp(search),
captureNames, result, str;

// There are many combinations of search/replacement types/values and browser bugs that
// preclude passing to native `replace`, so just keep this check relatively simple
if (isRegex && typeof replacement.valueOf() === "string" && replacement.indexOf("${") === -1 && compliantLastIndexReset)
return real.replace.apply(this, arguments);

if (!isRegex)
captureNames, result, str, origLastIndex;

// There are too many combinations of search/replacement types/values and browser bugs that
// preclude passing to native `replace`, so don't try
//if (...)
// return nativ.replace.apply(this, arguments);

if (isRegex) {
if (search._xregexp)
captureNames = search._xregexp.captureNames; // Array or `null`
if (!search.global)
origLastIndex = search.lastIndex;
} else {
search = search + ""; // Type conversion
else if (search._xregexp)
captureNames = search._xregexp.captureNames; // Array or `null`
}

if (typeof replacement === "function") {
result = real.replace.call(this, search, function () {
if (Object.prototype.toString.call(replacement) === "[object Function]") {
result = nativ.replace.call(this + "", search, function () {
if (captureNames) {
// Change the `arguments[0]` string primitive to a String object which can store properties
arguments[0] = new String(arguments[0]);
Expand All @@ -356,16 +366,16 @@ if (XRegExp) {
arguments[0][captureNames[i]] = arguments[i + 1];
}
}
// Update `lastIndex` before calling `replacement`
// Update `lastIndex` before calling `replacement` (fix browsers)
if (isRegex && search.global)
search.lastIndex = arguments[arguments.length - 2] + arguments[0].length;
return replacement.apply(null, arguments);
});
} else {
str = this + ""; // Type conversion, so `args[args.length - 1]` will be a string (given nonstring `this`)
result = real.replace.call(str, search, function () {
result = nativ.replace.call(str, search, function () {
var args = arguments; // Keep this function's `arguments` available through closure
return real.replace.call(replacement, replacementToken, function ($0, $1, $2) {
return nativ.replace.call(replacement + "", replacementToken, function ($0, $1, $2) {
// Numbered backreference (without delimiters) or special variable
if ($1) {
switch ($1) {
Expand Down Expand Up @@ -411,8 +421,12 @@ if (XRegExp) {
});
}

if (isRegex && search.global)
search.lastIndex = 0; // Fix IE bug
if (isRegex) {
if (search.global)
search.lastIndex = 0; // Fix IE, Safari bug (last tested IE 9.0.5, Safari 5.1.2 on Windows)
else
search.lastIndex = origLastIndex; // Fix IE, Opera bug (last tested IE 9.0.5, Opera 11.61 on Windows)
}

return result;
};
Expand All @@ -421,7 +435,7 @@ if (XRegExp) {
String.prototype.split = function (s /* separator */, limit) {
// If separator `s` is not a regex, use the native `split`
if (!XRegExp.isRegExp(s))
return real.split.apply(this, arguments);
return nativ.split.apply(this, arguments);

var str = this + "", // Type conversion
output = [],
Expand Down Expand Up @@ -465,7 +479,7 @@ if (XRegExp) {
}

if (lastLastIndex === str.length) {
if (!real.test.call(s, "") || lastLength)
if (!nativ.test.call(s, "") || lastLength)
output.push("");
} else {
output.push(str.slice(lastLastIndex));
Expand Down Expand Up @@ -494,15 +508,15 @@ if (XRegExp) {
};
}
return regex;
};
}

function getNativeFlags (regex) {
return (regex.global ? "g" : "") +
(regex.ignoreCase ? "i" : "") +
(regex.multiline ? "m" : "") +
(regex.extended ? "x" : "") + // Proposed for ES4; included in AS3
(regex.sticky ? "y" : "");
};
}

function runTokens (pattern, index, scope, context) {
var i = tokens.length,
Expand Down Expand Up @@ -531,7 +545,7 @@ if (XRegExp) {
isInsideConstructor = false;
}
return result;
};
}

function indexOf (array, item, from) {
if (Array.prototype.indexOf) // Use the native array method if available
Expand All @@ -541,7 +555,7 @@ if (XRegExp) {
return i;
}
return -1;
};
}


//---------------------------------
Expand All @@ -556,7 +570,7 @@ if (XRegExp) {
/\(\?#[^)]*\)/,
function (match) {
// Keep tokens separated unless the following token is a quantifier
return real.test.call(quantifier, match.input.slice(match.index + match[0].length)) ? "" : "(?:)";
return nativ.test.call(quantifier, match.input.slice(match.index + match[0].length)) ? "" : "(?:)";
}
);

Expand Down Expand Up @@ -618,7 +632,7 @@ if (XRegExp) {
/(?:\s+|#.*)+/,
function (match) {
// Keep tokens separated unless the following token is a quantifier
return real.test.call(quantifier, match.input.slice(match.index + match[0].length)) ? "" : "(?:)";
return nativ.test.call(quantifier, match.input.slice(match.index + match[0].length)) ? "" : "(?:)";
},
XRegExp.OUTSIDE_CLASS,
function () {return this.hasFlag("x");}
Expand Down Expand Up @@ -648,5 +662,3 @@ if (XRegExp) {

})();

// CommonJS
typeof(exports) != 'undefined' ? exports.XRegExp = XRegExp : null;

0 comments on commit d871c84

Please sign in to comment.