xregexp-rails 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,102 @@
1
+ /*
2
+ XRegExp Unicode plugin pack: Scripts 1.1
3
+ (c) 2010-2012 Steven Levithan
4
+ MIT License
5
+ <http://xregexp.com>
6
+
7
+ Uses the Unicode 6.1 character database:
8
+ <http://unicode.org/Public/6.1.0/ucd/Scripts.txt>
9
+
10
+ This package for the XRegExp Unicode plugin enables the 71 Unicode 6.1 scripts
11
+ in the Basic Multilingual Plane (U+0000-U+FFFF).
12
+
13
+ Example usage:
14
+
15
+ \p{Latin}
16
+ \p{Canadian Aboriginal}
17
+
18
+ Letter case, spaces, hyphens, and underscores are ignored in script names.
19
+ */
20
+
21
+ var XRegExp;
22
+
23
+ if (!(XRegExp && XRegExp.addUnicodePackage)) {
24
+ throw ReferenceError("XRegExp's Unicode plugin must be loaded before adding scripts");
25
+ }
26
+
27
+ XRegExp.addUnicodePackage({
28
+ Arabic: "0600-06040606-060B060D-061A061E0620-063F0641-064A0656-065E066A-066F0671-06DC06DE-06FF0750-077F08A008A2-08AC08E4-08FEFB50-FBC1FBD3-FD3DFD50-FD8FFD92-FDC7FDF0-FDFCFE70-FE74FE76-FEFC",
29
+ Armenian: "0531-05560559-055F0561-0587058A058FFB13-FB17",
30
+ Balinese: "1B00-1B4B1B50-1B7C",
31
+ Bamum: "A6A0-A6F7",
32
+ Batak: "1BC0-1BF31BFC-1BFF",
33
+ Bengali: "0981-09830985-098C098F09900993-09A809AA-09B009B209B6-09B909BC-09C409C709C809CB-09CE09D709DC09DD09DF-09E309E6-09FB",
34
+ Bopomofo: "02EA02EB3105-312D31A0-31BA",
35
+ Braille: "2800-28FF",
36
+ Buginese: "1A00-1A1B1A1E1A1F",
37
+ Buhid: "1740-1753",
38
+ Canadian_Aboriginal: "1400-167F18B0-18F5",
39
+ Cham: "AA00-AA36AA40-AA4DAA50-AA59AA5C-AA5F",
40
+ Cherokee: "13A0-13F4",
41
+ Common: "0000-0040005B-0060007B-00A900AB-00B900BB-00BF00D700F702B9-02DF02E5-02E902EC-02FF0374037E038503870589060C061B061F06400660-066906DD096409650E3F0FD5-0FD810FB16EB-16ED173517361802180318051CD31CE11CE9-1CEC1CEE-1CF31CF51CF62000-200B200E-2064206A-20702074-207E2080-208E20A0-20B92100-21252127-2129212C-21312133-214D214F-215F21892190-23F32400-24262440-244A2460-26FF2701-27FF2900-2B4C2B50-2B592E00-2E3B2FF0-2FFB3000-300430063008-30203030-3037303C-303F309B309C30A030FB30FC3190-319F31C0-31E33220-325F327F-32CF3358-33FF4DC0-4DFFA700-A721A788-A78AA830-A839FD3EFD3FFDFDFE10-FE19FE30-FE52FE54-FE66FE68-FE6BFEFFFF01-FF20FF3B-FF40FF5B-FF65FF70FF9EFF9FFFE0-FFE6FFE8-FFEEFFF9-FFFD",
42
+ Coptic: "03E2-03EF2C80-2CF32CF9-2CFF",
43
+ Cyrillic: "0400-04840487-05271D2B1D782DE0-2DFFA640-A697A69F",
44
+ Devanagari: "0900-09500953-09630966-09770979-097FA8E0-A8FB",
45
+ Ethiopic: "1200-1248124A-124D1250-12561258125A-125D1260-1288128A-128D1290-12B012B2-12B512B8-12BE12C012C2-12C512C8-12D612D8-13101312-13151318-135A135D-137C1380-13992D80-2D962DA0-2DA62DA8-2DAE2DB0-2DB62DB8-2DBE2DC0-2DC62DC8-2DCE2DD0-2DD62DD8-2DDEAB01-AB06AB09-AB0EAB11-AB16AB20-AB26AB28-AB2E",
46
+ Georgian: "10A0-10C510C710CD10D0-10FA10FC-10FF2D00-2D252D272D2D",
47
+ Glagolitic: "2C00-2C2E2C30-2C5E",
48
+ Greek: "0370-03730375-0377037A-037D038403860388-038A038C038E-03A103A3-03E103F0-03FF1D26-1D2A1D5D-1D611D66-1D6A1DBF1F00-1F151F18-1F1D1F20-1F451F48-1F4D1F50-1F571F591F5B1F5D1F5F-1F7D1F80-1FB41FB6-1FC41FC6-1FD31FD6-1FDB1FDD-1FEF1FF2-1FF41FF6-1FFE2126",
49
+ Gujarati: "0A81-0A830A85-0A8D0A8F-0A910A93-0AA80AAA-0AB00AB20AB30AB5-0AB90ABC-0AC50AC7-0AC90ACB-0ACD0AD00AE0-0AE30AE6-0AF1",
50
+ Gurmukhi: "0A01-0A030A05-0A0A0A0F0A100A13-0A280A2A-0A300A320A330A350A360A380A390A3C0A3E-0A420A470A480A4B-0A4D0A510A59-0A5C0A5E0A66-0A75",
51
+ Han: "2E80-2E992E9B-2EF32F00-2FD5300530073021-30293038-303B3400-4DB54E00-9FCCF900-FA6DFA70-FAD9",
52
+ Hangul: "1100-11FF302E302F3131-318E3200-321E3260-327EA960-A97CAC00-D7A3D7B0-D7C6D7CB-D7FBFFA0-FFBEFFC2-FFC7FFCA-FFCFFFD2-FFD7FFDA-FFDC",
53
+ Hanunoo: "1720-1734",
54
+ Hebrew: "0591-05C705D0-05EA05F0-05F4FB1D-FB36FB38-FB3CFB3EFB40FB41FB43FB44FB46-FB4F",
55
+ Hiragana: "3041-3096309D-309F",
56
+ Inherited: "0300-036F04850486064B-0655065F0670095109521CD0-1CD21CD4-1CE01CE2-1CE81CED1CF41DC0-1DE61DFC-1DFF200C200D20D0-20F0302A-302D3099309AFE00-FE0FFE20-FE26",
57
+ Javanese: "A980-A9CDA9CF-A9D9A9DEA9DF",
58
+ Kannada: "0C820C830C85-0C8C0C8E-0C900C92-0CA80CAA-0CB30CB5-0CB90CBC-0CC40CC6-0CC80CCA-0CCD0CD50CD60CDE0CE0-0CE30CE6-0CEF0CF10CF2",
59
+ Katakana: "30A1-30FA30FD-30FF31F0-31FF32D0-32FE3300-3357FF66-FF6FFF71-FF9D",
60
+ Kayah_Li: "A900-A92F",
61
+ Khmer: "1780-17DD17E0-17E917F0-17F919E0-19FF",
62
+ Lao: "0E810E820E840E870E880E8A0E8D0E94-0E970E99-0E9F0EA1-0EA30EA50EA70EAA0EAB0EAD-0EB90EBB-0EBD0EC0-0EC40EC60EC8-0ECD0ED0-0ED90EDC-0EDF",
63
+ Latin: "0041-005A0061-007A00AA00BA00C0-00D600D8-00F600F8-02B802E0-02E41D00-1D251D2C-1D5C1D62-1D651D6B-1D771D79-1DBE1E00-1EFF2071207F2090-209C212A212B2132214E2160-21882C60-2C7FA722-A787A78B-A78EA790-A793A7A0-A7AAA7F8-A7FFFB00-FB06FF21-FF3AFF41-FF5A",
64
+ Lepcha: "1C00-1C371C3B-1C491C4D-1C4F",
65
+ Limbu: "1900-191C1920-192B1930-193B19401944-194F",
66
+ Lisu: "A4D0-A4FF",
67
+ Malayalam: "0D020D030D05-0D0C0D0E-0D100D12-0D3A0D3D-0D440D46-0D480D4A-0D4E0D570D60-0D630D66-0D750D79-0D7F",
68
+ Mandaic: "0840-085B085E",
69
+ Meetei_Mayek: "AAE0-AAF6ABC0-ABEDABF0-ABF9",
70
+ Mongolian: "1800180118041806-180E1810-18191820-18771880-18AA",
71
+ Myanmar: "1000-109FAA60-AA7B",
72
+ New_Tai_Lue: "1980-19AB19B0-19C919D0-19DA19DE19DF",
73
+ NKo: "07C0-07FA",
74
+ Ogham: "1680-169C",
75
+ Ol_Chiki: "1C50-1C7F",
76
+ Oriya: "0B01-0B030B05-0B0C0B0F0B100B13-0B280B2A-0B300B320B330B35-0B390B3C-0B440B470B480B4B-0B4D0B560B570B5C0B5D0B5F-0B630B66-0B77",
77
+ Phags_Pa: "A840-A877",
78
+ Rejang: "A930-A953A95F",
79
+ Runic: "16A0-16EA16EE-16F0",
80
+ Samaritan: "0800-082D0830-083E",
81
+ Saurashtra: "A880-A8C4A8CE-A8D9",
82
+ Sinhala: "0D820D830D85-0D960D9A-0DB10DB3-0DBB0DBD0DC0-0DC60DCA0DCF-0DD40DD60DD8-0DDF0DF2-0DF4",
83
+ Sundanese: "1B80-1BBF1CC0-1CC7",
84
+ Syloti_Nagri: "A800-A82B",
85
+ Syriac: "0700-070D070F-074A074D-074F",
86
+ Tagalog: "1700-170C170E-1714",
87
+ Tagbanwa: "1760-176C176E-177017721773",
88
+ Tai_Le: "1950-196D1970-1974",
89
+ Tai_Tham: "1A20-1A5E1A60-1A7C1A7F-1A891A90-1A991AA0-1AAD",
90
+ Tai_Viet: "AA80-AAC2AADB-AADF",
91
+ Tamil: "0B820B830B85-0B8A0B8E-0B900B92-0B950B990B9A0B9C0B9E0B9F0BA30BA40BA8-0BAA0BAE-0BB90BBE-0BC20BC6-0BC80BCA-0BCD0BD00BD70BE6-0BFA",
92
+ Telugu: "0C01-0C030C05-0C0C0C0E-0C100C12-0C280C2A-0C330C35-0C390C3D-0C440C46-0C480C4A-0C4D0C550C560C580C590C60-0C630C66-0C6F0C78-0C7F",
93
+ Thaana: "0780-07B1",
94
+ Thai: "0E01-0E3A0E40-0E5B",
95
+ Tibetan: "0F00-0F470F49-0F6C0F71-0F970F99-0FBC0FBE-0FCC0FCE-0FD40FD90FDA",
96
+ Tifinagh: "2D30-2D672D6F2D702D7F",
97
+ Vai: "A500-A62B",
98
+ Yi: "A000-A48CA490-A4C6"
99
+ });
100
+
101
+ // Excludes 31 Unicode 6.1 scripts with no code points in the BMP.
102
+
@@ -0,0 +1,664 @@
1
+ // XRegExp 1.5.1
2
+ // (c) 2007-2012 Steven Levithan
3
+ // MIT License
4
+ // <http://xregexp.com>
5
+ // Provides an augmented, extensible, cross-browser implementation of regular expressions,
6
+ // including support for additional syntax, flags, and methods
7
+
8
+ var XRegExp;
9
+
10
+ if (XRegExp) {
11
+ // Avoid running twice, since that would break references to native globals
12
+ throw Error("can't load XRegExp twice in the same frame");
13
+ }
14
+
15
+ // Run within an anonymous function to protect variables and avoid new globals
16
+ (function (undefined) {
17
+
18
+ //---------------------------------
19
+ // Constructor
20
+ //---------------------------------
21
+
22
+ // Accepts a pattern and flags; returns a new, extended `RegExp` object. Differs from a native
23
+ // regular expression in that additional syntax and flags are supported and cross-browser
24
+ // syntax inconsistencies are ameliorated. `XRegExp(/regex/)` clones an existing regex and
25
+ // converts to type XRegExp
26
+ XRegExp = function (pattern, flags) {
27
+ var output = [],
28
+ currScope = XRegExp.OUTSIDE_CLASS,
29
+ pos = 0,
30
+ context, tokenResult, match, chr, regex;
31
+
32
+ if (XRegExp.isRegExp(pattern)) {
33
+ if (flags !== undefined)
34
+ throw TypeError("can't supply flags when constructing one RegExp from another");
35
+ return clone(pattern);
36
+ }
37
+ // Tokens become part of the regex construction process, so protect against infinite
38
+ // recursion when an XRegExp is constructed within a token handler or trigger
39
+ if (isInsideConstructor)
40
+ throw Error("can't call the XRegExp constructor within token definition functions");
41
+
42
+ flags = flags || "";
43
+ context = { // `this` object for custom tokens
44
+ hasNamedCapture: false,
45
+ captureNames: [],
46
+ hasFlag: function (flag) {return flags.indexOf(flag) > -1;},
47
+ setFlag: function (flag) {flags += flag;}
48
+ };
49
+
50
+ while (pos < pattern.length) {
51
+ // Check for custom tokens at the current position
52
+ tokenResult = runTokens(pattern, pos, currScope, context);
53
+
54
+ if (tokenResult) {
55
+ output.push(tokenResult.output);
56
+ pos += (tokenResult.match[0].length || 1);
57
+ } else {
58
+ // Check for native multicharacter metasequences (excluding character classes) at
59
+ // the current position
60
+ if (match = nativ.exec.call(nativeTokens[currScope], pattern.slice(pos))) {
61
+ output.push(match[0]);
62
+ pos += match[0].length;
63
+ } else {
64
+ chr = pattern.charAt(pos);
65
+ if (chr === "[")
66
+ currScope = XRegExp.INSIDE_CLASS;
67
+ else if (chr === "]")
68
+ currScope = XRegExp.OUTSIDE_CLASS;
69
+ // Advance position one character
70
+ output.push(chr);
71
+ pos++;
72
+ }
73
+ }
74
+ }
75
+
76
+ regex = RegExp(output.join(""), nativ.replace.call(flags, flagClip, ""));
77
+ regex._xregexp = {
78
+ source: pattern,
79
+ captureNames: context.hasNamedCapture ? context.captureNames : null
80
+ };
81
+ return regex;
82
+ };
83
+
84
+
85
+ //---------------------------------
86
+ // Public properties
87
+ //---------------------------------
88
+
89
+ XRegExp.version = "1.5.1";
90
+
91
+ // Token scope bitflags
92
+ XRegExp.INSIDE_CLASS = 1;
93
+ XRegExp.OUTSIDE_CLASS = 2;
94
+
95
+
96
+ //---------------------------------
97
+ // Private variables
98
+ //---------------------------------
99
+
100
+ var replacementToken = /\$(?:(\d\d?|[$&`'])|{([$\w]+)})/g,
101
+ flagClip = /[^gimy]+|([\s\S])(?=[\s\S]*\1)/g, // Nonnative and duplicate flags
102
+ quantifier = /^(?:[?*+]|{\d+(?:,\d*)?})\??/,
103
+ isInsideConstructor = false,
104
+ tokens = [],
105
+ // Copy native globals for reference ("native" is an ES3 reserved keyword)
106
+ nativ = {
107
+ exec: RegExp.prototype.exec,
108
+ test: RegExp.prototype.test,
109
+ match: String.prototype.match,
110
+ replace: String.prototype.replace,
111
+ split: String.prototype.split
112
+ },
113
+ compliantExecNpcg = nativ.exec.call(/()??/, "")[1] === undefined, // check `exec` handling of nonparticipating capturing groups
114
+ compliantLastIndexIncrement = function () {
115
+ var x = /^/g;
116
+ nativ.test.call(x, "");
117
+ return !x.lastIndex;
118
+ }(),
119
+ hasNativeY = RegExp.prototype.sticky !== undefined,
120
+ nativeTokens = {};
121
+
122
+ // `nativeTokens` match native multicharacter metasequences only (including deprecated octals,
123
+ // excluding character classes)
124
+ 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]))/;
125
+ 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*)?}\??)/;
126
+
127
+
128
+ //---------------------------------
129
+ // Public methods
130
+ //---------------------------------
131
+
132
+ // Lets you extend or change XRegExp syntax and create custom flags. This is used internally by
133
+ // the XRegExp library and can be used to create XRegExp plugins. This function is intended for
134
+ // users with advanced knowledge of JavaScript's regular expression syntax and behavior. It can
135
+ // be disabled by `XRegExp.freezeTokens`
136
+ XRegExp.addToken = function (regex, handler, scope, trigger) {
137
+ tokens.push({
138
+ pattern: clone(regex, "g" + (hasNativeY ? "y" : "")),
139
+ handler: handler,
140
+ scope: scope || XRegExp.OUTSIDE_CLASS,
141
+ trigger: trigger || null
142
+ });
143
+ };
144
+
145
+ // Accepts a pattern and flags; returns an extended `RegExp` object. If the pattern and flag
146
+ // combination has previously been cached, the cached copy is returned; otherwise the newly
147
+ // created regex is cached
148
+ XRegExp.cache = function (pattern, flags) {
149
+ var key = pattern + "/" + (flags || "");
150
+ return XRegExp.cache[key] || (XRegExp.cache[key] = XRegExp(pattern, flags));
151
+ };
152
+
153
+ // Accepts a `RegExp` instance; returns a copy with the `/g` flag set. The copy has a fresh
154
+ // `lastIndex` (set to zero). If you want to copy a regex without forcing the `global`
155
+ // property, use `XRegExp(regex)`. Do not use `RegExp(regex)` because it will not preserve
156
+ // special properties required for named capture
157
+ XRegExp.copyAsGlobal = function (regex) {
158
+ return clone(regex, "g");
159
+ };
160
+
161
+ // Accepts a string; returns the string with regex metacharacters escaped. The returned string
162
+ // can safely be used at any point within a regex to match the provided literal string. Escaped
163
+ // characters are [ ] { } ( ) * + ? - . , \ ^ $ | # and whitespace
164
+ XRegExp.escape = function (str) {
165
+ return str.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
166
+ };
167
+
168
+ // Accepts a string to search, regex to search with, position to start the search within the
169
+ // string (default: 0), and an optional Boolean indicating whether matches must start at-or-
170
+ // after the position or at the specified position only. This function ignores the `lastIndex`
171
+ // of the provided regex in its own handling, but updates the property for compatibility
172
+ XRegExp.execAt = function (str, regex, pos, anchored) {
173
+ var r2 = clone(regex, "g" + ((anchored && hasNativeY) ? "y" : "")),
174
+ match;
175
+ r2.lastIndex = pos = pos || 0;
176
+ match = r2.exec(str); // Run the altered `exec` (required for `lastIndex` fix, etc.)
177
+ if (anchored && match && match.index !== pos)
178
+ match = null;
179
+ if (regex.global)
180
+ regex.lastIndex = match ? r2.lastIndex : 0;
181
+ return match;
182
+ };
183
+
184
+ // Breaks the unrestorable link to XRegExp's private list of tokens, thereby preventing
185
+ // syntax and flag changes. Should be run after XRegExp and any plugins are loaded
186
+ XRegExp.freezeTokens = function () {
187
+ XRegExp.addToken = function () {
188
+ throw Error("can't run addToken after freezeTokens");
189
+ };
190
+ };
191
+
192
+ // Accepts any value; returns a Boolean indicating whether the argument is a `RegExp` object.
193
+ // Note that this is also `true` for regex literals and regexes created by the `XRegExp`
194
+ // constructor. This works correctly for variables created in another frame, when `instanceof`
195
+ // and `constructor` checks would fail to work as intended
196
+ XRegExp.isRegExp = function (o) {
197
+ return Object.prototype.toString.call(o) === "[object RegExp]";
198
+ };
199
+
200
+ // Executes `callback` once per match within `str`. Provides a simpler and cleaner way to
201
+ // iterate over regex matches compared to the traditional approaches of subverting
202
+ // `String.prototype.replace` or repeatedly calling `exec` within a `while` loop
203
+ XRegExp.iterate = function (str, regex, callback, context) {
204
+ var r2 = clone(regex, "g"),
205
+ i = -1, match;
206
+ while (match = r2.exec(str)) { // Run the altered `exec` (required for `lastIndex` fix, etc.)
207
+ if (regex.global)
208
+ regex.lastIndex = r2.lastIndex; // Doing this to follow expectations if `lastIndex` is checked within `callback`
209
+ callback.call(context, match, ++i, str, regex);
210
+ if (r2.lastIndex === match.index)
211
+ r2.lastIndex++;
212
+ }
213
+ if (regex.global)
214
+ regex.lastIndex = 0;
215
+ };
216
+
217
+ // Accepts a string and an array of regexes; returns the result of using each successive regex
218
+ // to search within the matches of the previous regex. The array of regexes can also contain
219
+ // objects with `regex` and `backref` properties, in which case the named or numbered back-
220
+ // references specified are passed forward to the next regex or returned. E.g.:
221
+ // var xregexpImgFileNames = XRegExp.matchChain(html, [
222
+ // {regex: /<img\b([^>]+)>/i, backref: 1}, // <img> tag attributes
223
+ // {regex: XRegExp('(?ix) \\s src=" (?<src> [^"]+ )'), backref: "src"}, // src attribute values
224
+ // {regex: XRegExp("^http://xregexp\\.com(/[^#?]+)", "i"), backref: 1}, // xregexp.com paths
225
+ // /[^\/]+$/ // filenames (strip directory paths)
226
+ // ]);
227
+ XRegExp.matchChain = function (str, chain) {
228
+ return function recurseChain (values, level) {
229
+ var item = chain[level].regex ? chain[level] : {regex: chain[level]},
230
+ regex = clone(item.regex, "g"),
231
+ matches = [], i;
232
+ for (i = 0; i < values.length; i++) {
233
+ XRegExp.iterate(values[i], regex, function (match) {
234
+ matches.push(item.backref ? (match[item.backref] || "") : match[0]);
235
+ });
236
+ }
237
+ return ((level === chain.length - 1) || !matches.length) ?
238
+ matches : recurseChain(matches, level + 1);
239
+ }([str], 0);
240
+ };
241
+
242
+
243
+ //---------------------------------
244
+ // New RegExp prototype methods
245
+ //---------------------------------
246
+
247
+ // Accepts a context object and arguments array; returns the result of calling `exec` with the
248
+ // first value in the arguments array. the context is ignored but is accepted for congruity
249
+ // with `Function.prototype.apply`
250
+ RegExp.prototype.apply = function (context, args) {
251
+ return this.exec(args[0]);
252
+ };
253
+
254
+ // Accepts a context object and string; returns the result of calling `exec` with the provided
255
+ // string. the context is ignored but is accepted for congruity with `Function.prototype.call`
256
+ RegExp.prototype.call = function (context, str) {
257
+ return this.exec(str);
258
+ };
259
+
260
+
261
+ //---------------------------------
262
+ // Overriden native methods
263
+ //---------------------------------
264
+
265
+ // Adds named capture support (with backreferences returned as `result.name`), and fixes two
266
+ // cross-browser issues per ES3:
267
+ // - Captured values for nonparticipating capturing groups should be returned as `undefined`,
268
+ // rather than the empty string.
269
+ // - `lastIndex` should not be incremented after zero-length matches.
270
+ RegExp.prototype.exec = function (str) {
271
+ var match, name, r2, origLastIndex;
272
+ if (!this.global)
273
+ origLastIndex = this.lastIndex;
274
+ match = nativ.exec.apply(this, arguments);
275
+ if (match) {
276
+ // Fix browsers whose `exec` methods don't consistently return `undefined` for
277
+ // nonparticipating capturing groups
278
+ if (!compliantExecNpcg && match.length > 1 && indexOf(match, "") > -1) {
279
+ r2 = RegExp(this.source, nativ.replace.call(getNativeFlags(this), "g", ""));
280
+ // Using `str.slice(match.index)` rather than `match[0]` in case lookahead allowed
281
+ // matching due to characters outside the match
282
+ nativ.replace.call((str + "").slice(match.index), r2, function () {
283
+ for (var i = 1; i < arguments.length - 2; i++) {
284
+ if (arguments[i] === undefined)
285
+ match[i] = undefined;
286
+ }
287
+ });
288
+ }
289
+ // Attach named capture properties
290
+ if (this._xregexp && this._xregexp.captureNames) {
291
+ for (var i = 1; i < match.length; i++) {
292
+ name = this._xregexp.captureNames[i - 1];
293
+ if (name)
294
+ match[name] = match[i];
295
+ }
296
+ }
297
+ // Fix browsers that increment `lastIndex` after zero-length matches
298
+ if (!compliantLastIndexIncrement && this.global && !match[0].length && (this.lastIndex > match.index))
299
+ this.lastIndex--;
300
+ }
301
+ if (!this.global)
302
+ this.lastIndex = origLastIndex; // Fix IE, Opera bug (last tested IE 9.0.5, Opera 11.61 on Windows)
303
+ return match;
304
+ };
305
+
306
+ // Fix browser bugs in native method
307
+ RegExp.prototype.test = function (str) {
308
+ // Use the native `exec` to skip some processing overhead, even though the altered
309
+ // `exec` would take care of the `lastIndex` fixes
310
+ var match, origLastIndex;
311
+ if (!this.global)
312
+ origLastIndex = this.lastIndex;
313
+ match = nativ.exec.call(this, str);
314
+ // Fix browsers that increment `lastIndex` after zero-length matches
315
+ if (match && !compliantLastIndexIncrement && this.global && !match[0].length && (this.lastIndex > match.index))
316
+ this.lastIndex--;
317
+ if (!this.global)
318
+ this.lastIndex = origLastIndex; // Fix IE, Opera bug (last tested IE 9.0.5, Opera 11.61 on Windows)
319
+ return !!match;
320
+ };
321
+
322
+ // Adds named capture support and fixes browser bugs in native method
323
+ String.prototype.match = function (regex) {
324
+ if (!XRegExp.isRegExp(regex))
325
+ regex = RegExp(regex); // Native `RegExp`
326
+ if (regex.global) {
327
+ var result = nativ.match.apply(this, arguments);
328
+ regex.lastIndex = 0; // Fix IE bug
329
+ return result;
330
+ }
331
+ return regex.exec(this); // Run the altered `exec`
332
+ };
333
+
334
+ // Adds support for `${n}` tokens for named and numbered backreferences in replacement text,
335
+ // and provides named backreferences to replacement functions as `arguments[0].name`. Also
336
+ // fixes cross-browser differences in replacement text syntax when performing a replacement
337
+ // using a nonregex search value, and the value of replacement regexes' `lastIndex` property
338
+ // during replacement iterations. Note that this doesn't support SpiderMonkey's proprietary
339
+ // third (`flags`) parameter
340
+ String.prototype.replace = function (search, replacement) {
341
+ var isRegex = XRegExp.isRegExp(search),
342
+ captureNames, result, str, origLastIndex;
343
+
344
+ // There are too many combinations of search/replacement types/values and browser bugs that
345
+ // preclude passing to native `replace`, so don't try
346
+ //if (...)
347
+ // return nativ.replace.apply(this, arguments);
348
+
349
+ if (isRegex) {
350
+ if (search._xregexp)
351
+ captureNames = search._xregexp.captureNames; // Array or `null`
352
+ if (!search.global)
353
+ origLastIndex = search.lastIndex;
354
+ } else {
355
+ search = search + ""; // Type conversion
356
+ }
357
+
358
+ if (Object.prototype.toString.call(replacement) === "[object Function]") {
359
+ result = nativ.replace.call(this + "", search, function () {
360
+ if (captureNames) {
361
+ // Change the `arguments[0]` string primitive to a String object which can store properties
362
+ arguments[0] = new String(arguments[0]);
363
+ // Store named backreferences on `arguments[0]`
364
+ for (var i = 0; i < captureNames.length; i++) {
365
+ if (captureNames[i])
366
+ arguments[0][captureNames[i]] = arguments[i + 1];
367
+ }
368
+ }
369
+ // Update `lastIndex` before calling `replacement` (fix browsers)
370
+ if (isRegex && search.global)
371
+ search.lastIndex = arguments[arguments.length - 2] + arguments[0].length;
372
+ return replacement.apply(null, arguments);
373
+ });
374
+ } else {
375
+ str = this + ""; // Type conversion, so `args[args.length - 1]` will be a string (given nonstring `this`)
376
+ result = nativ.replace.call(str, search, function () {
377
+ var args = arguments; // Keep this function's `arguments` available through closure
378
+ return nativ.replace.call(replacement + "", replacementToken, function ($0, $1, $2) {
379
+ // Numbered backreference (without delimiters) or special variable
380
+ if ($1) {
381
+ switch ($1) {
382
+ case "$": return "$";
383
+ case "&": return args[0];
384
+ case "`": return args[args.length - 1].slice(0, args[args.length - 2]);
385
+ case "'": return args[args.length - 1].slice(args[args.length - 2] + args[0].length);
386
+ // Numbered backreference
387
+ default:
388
+ // What does "$10" mean?
389
+ // - Backreference 10, if 10 or more capturing groups exist
390
+ // - Backreference 1 followed by "0", if 1-9 capturing groups exist
391
+ // - Otherwise, it's the string "$10"
392
+ // Also note:
393
+ // - Backreferences cannot be more than two digits (enforced by `replacementToken`)
394
+ // - "$01" is equivalent to "$1" if a capturing group exists, otherwise it's the string "$01"
395
+ // - There is no "$0" token ("$&" is the entire match)
396
+ var literalNumbers = "";
397
+ $1 = +$1; // Type conversion; drop leading zero
398
+ if (!$1) // `$1` was "0" or "00"
399
+ return $0;
400
+ while ($1 > args.length - 3) {
401
+ literalNumbers = String.prototype.slice.call($1, -1) + literalNumbers;
402
+ $1 = Math.floor($1 / 10); // Drop the last digit
403
+ }
404
+ return ($1 ? args[$1] || "" : "$") + literalNumbers;
405
+ }
406
+ // Named backreference or delimited numbered backreference
407
+ } else {
408
+ // What does "${n}" mean?
409
+ // - Backreference to numbered capture n. Two differences from "$n":
410
+ // - n can be more than two digits
411
+ // - Backreference 0 is allowed, and is the entire match
412
+ // - Backreference to named capture n, if it exists and is not a number overridden by numbered capture
413
+ // - Otherwise, it's the string "${n}"
414
+ var n = +$2; // Type conversion; drop leading zeros
415
+ if (n <= args.length - 3)
416
+ return args[n];
417
+ n = captureNames ? indexOf(captureNames, $2) : -1;
418
+ return n > -1 ? args[n + 1] : $0;
419
+ }
420
+ });
421
+ });
422
+ }
423
+
424
+ if (isRegex) {
425
+ if (search.global)
426
+ search.lastIndex = 0; // Fix IE, Safari bug (last tested IE 9.0.5, Safari 5.1.2 on Windows)
427
+ else
428
+ search.lastIndex = origLastIndex; // Fix IE, Opera bug (last tested IE 9.0.5, Opera 11.61 on Windows)
429
+ }
430
+
431
+ return result;
432
+ };
433
+
434
+ // A consistent cross-browser, ES3 compliant `split`
435
+ String.prototype.split = function (s /* separator */, limit) {
436
+ // If separator `s` is not a regex, use the native `split`
437
+ if (!XRegExp.isRegExp(s))
438
+ return nativ.split.apply(this, arguments);
439
+
440
+ var str = this + "", // Type conversion
441
+ output = [],
442
+ lastLastIndex = 0,
443
+ match, lastLength;
444
+
445
+ // Behavior for `limit`: if it's...
446
+ // - `undefined`: No limit
447
+ // - `NaN` or zero: Return an empty array
448
+ // - A positive number: Use `Math.floor(limit)`
449
+ // - A negative number: No limit
450
+ // - Other: Type-convert, then use the above rules
451
+ if (limit === undefined || +limit < 0) {
452
+ limit = Infinity;
453
+ } else {
454
+ limit = Math.floor(+limit);
455
+ if (!limit)
456
+ return [];
457
+ }
458
+
459
+ // This is required if not `s.global`, and it avoids needing to set `s.lastIndex` to zero
460
+ // and restore it to its original value when we're done using the regex
461
+ s = XRegExp.copyAsGlobal(s);
462
+
463
+ while (match = s.exec(str)) { // Run the altered `exec` (required for `lastIndex` fix, etc.)
464
+ if (s.lastIndex > lastLastIndex) {
465
+ output.push(str.slice(lastLastIndex, match.index));
466
+
467
+ if (match.length > 1 && match.index < str.length)
468
+ Array.prototype.push.apply(output, match.slice(1));
469
+
470
+ lastLength = match[0].length;
471
+ lastLastIndex = s.lastIndex;
472
+
473
+ if (output.length >= limit)
474
+ break;
475
+ }
476
+
477
+ if (s.lastIndex === match.index)
478
+ s.lastIndex++;
479
+ }
480
+
481
+ if (lastLastIndex === str.length) {
482
+ if (!nativ.test.call(s, "") || lastLength)
483
+ output.push("");
484
+ } else {
485
+ output.push(str.slice(lastLastIndex));
486
+ }
487
+
488
+ return output.length > limit ? output.slice(0, limit) : output;
489
+ };
490
+
491
+
492
+ //---------------------------------
493
+ // Private helper functions
494
+ //---------------------------------
495
+
496
+ // Supporting function for `XRegExp`, `XRegExp.copyAsGlobal`, etc. Returns a copy of a `RegExp`
497
+ // instance with a fresh `lastIndex` (set to zero), preserving properties required for named
498
+ // capture. Also allows adding new flags in the process of copying the regex
499
+ function clone (regex, additionalFlags) {
500
+ if (!XRegExp.isRegExp(regex))
501
+ throw TypeError("type RegExp expected");
502
+ var x = regex._xregexp;
503
+ regex = XRegExp(regex.source, getNativeFlags(regex) + (additionalFlags || ""));
504
+ if (x) {
505
+ regex._xregexp = {
506
+ source: x.source,
507
+ captureNames: x.captureNames ? x.captureNames.slice(0) : null
508
+ };
509
+ }
510
+ return regex;
511
+ }
512
+
513
+ function getNativeFlags (regex) {
514
+ return (regex.global ? "g" : "") +
515
+ (regex.ignoreCase ? "i" : "") +
516
+ (regex.multiline ? "m" : "") +
517
+ (regex.extended ? "x" : "") + // Proposed for ES4; included in AS3
518
+ (regex.sticky ? "y" : "");
519
+ }
520
+
521
+ function runTokens (pattern, index, scope, context) {
522
+ var i = tokens.length,
523
+ result, match, t;
524
+ // Protect against constructing XRegExps within token handler and trigger functions
525
+ isInsideConstructor = true;
526
+ // Must reset `isInsideConstructor`, even if a `trigger` or `handler` throws
527
+ try {
528
+ while (i--) { // Run in reverse order
529
+ t = tokens[i];
530
+ if ((scope & t.scope) && (!t.trigger || t.trigger.call(context))) {
531
+ t.pattern.lastIndex = index;
532
+ match = t.pattern.exec(pattern); // Running the altered `exec` here allows use of named backreferences, etc.
533
+ if (match && match.index === index) {
534
+ result = {
535
+ output: t.handler.call(context, match, scope),
536
+ match: match
537
+ };
538
+ break;
539
+ }
540
+ }
541
+ }
542
+ } catch (err) {
543
+ throw err;
544
+ } finally {
545
+ isInsideConstructor = false;
546
+ }
547
+ return result;
548
+ }
549
+
550
+ function indexOf (array, item, from) {
551
+ if (Array.prototype.indexOf) // Use the native array method if available
552
+ return array.indexOf(item, from);
553
+ for (var i = from || 0; i < array.length; i++) {
554
+ if (array[i] === item)
555
+ return i;
556
+ }
557
+ return -1;
558
+ }
559
+
560
+
561
+ //---------------------------------
562
+ // Built-in tokens
563
+ //---------------------------------
564
+
565
+ // Augment XRegExp's regular expression syntax and flags. Note that when adding tokens, the
566
+ // third (`scope`) argument defaults to `XRegExp.OUTSIDE_CLASS`
567
+
568
+ // Comment pattern: (?# )
569
+ XRegExp.addToken(
570
+ /\(\?#[^)]*\)/,
571
+ function (match) {
572
+ // Keep tokens separated unless the following token is a quantifier
573
+ return nativ.test.call(quantifier, match.input.slice(match.index + match[0].length)) ? "" : "(?:)";
574
+ }
575
+ );
576
+
577
+ // Capturing group (match the opening parenthesis only).
578
+ // Required for support of named capturing groups
579
+ XRegExp.addToken(
580
+ /\((?!\?)/,
581
+ function () {
582
+ this.captureNames.push(null);
583
+ return "(";
584
+ }
585
+ );
586
+
587
+ // Named capturing group (match the opening delimiter only): (?<name>
588
+ XRegExp.addToken(
589
+ /\(\?<([$\w]+)>/,
590
+ function (match) {
591
+ this.captureNames.push(match[1]);
592
+ this.hasNamedCapture = true;
593
+ return "(";
594
+ }
595
+ );
596
+
597
+ // Named backreference: \k<name>
598
+ XRegExp.addToken(
599
+ /\\k<([\w$]+)>/,
600
+ function (match) {
601
+ var index = indexOf(this.captureNames, match[1]);
602
+ // Keep backreferences separate from subsequent literal numbers. Preserve back-
603
+ // references to named groups that are undefined at this point as literal strings
604
+ return index > -1 ?
605
+ "\\" + (index + 1) + (isNaN(match.input.charAt(match.index + match[0].length)) ? "" : "(?:)") :
606
+ match[0];
607
+ }
608
+ );
609
+
610
+ // Empty character class: [] or [^]
611
+ XRegExp.addToken(
612
+ /\[\^?]/,
613
+ function (match) {
614
+ // For cross-browser compatibility with ES3, convert [] to \b\B and [^] to [\s\S].
615
+ // (?!) should work like \b\B, but is unreliable in Firefox
616
+ return match[0] === "[]" ? "\\b\\B" : "[\\s\\S]";
617
+ }
618
+ );
619
+
620
+ // Mode modifier at the start of the pattern only, with any combination of flags imsx: (?imsx)
621
+ // Does not support x(?i), (?-i), (?i-m), (?i: ), (?i)(?m), etc.
622
+ XRegExp.addToken(
623
+ /^\(\?([imsx]+)\)/,
624
+ function (match) {
625
+ this.setFlag(match[1]);
626
+ return "";
627
+ }
628
+ );
629
+
630
+ // Whitespace and comments, in free-spacing (aka extended) mode only
631
+ XRegExp.addToken(
632
+ /(?:\s+|#.*)+/,
633
+ function (match) {
634
+ // Keep tokens separated unless the following token is a quantifier
635
+ return nativ.test.call(quantifier, match.input.slice(match.index + match[0].length)) ? "" : "(?:)";
636
+ },
637
+ XRegExp.OUTSIDE_CLASS,
638
+ function () {return this.hasFlag("x");}
639
+ );
640
+
641
+ // Dot, in dotall (aka singleline) mode only
642
+ XRegExp.addToken(
643
+ /\./,
644
+ function () {return "[\\s\\S]";},
645
+ XRegExp.OUTSIDE_CLASS,
646
+ function () {return this.hasFlag("s");}
647
+ );
648
+
649
+
650
+ //---------------------------------
651
+ // Backward compatibility
652
+ //---------------------------------
653
+
654
+ // Uncomment the following block for compatibility with XRegExp 1.0-1.2:
655
+ /*
656
+ XRegExp.matchWithinChain = XRegExp.matchChain;
657
+ RegExp.prototype.addFlags = function (s) {return clone(this, s);};
658
+ RegExp.prototype.execAll = function (s) {var r = []; XRegExp.iterate(s, this, function (m) {r.push(m);}); return r;};
659
+ RegExp.prototype.forEachExec = function (s, f, c) {return XRegExp.iterate(s, this, f, c);};
660
+ RegExp.prototype.validate = function (s) {var r = RegExp("^(?:" + this.source + ")$(?!\\s)", getNativeFlags(this)); if (this.global) this.lastIndex = 0; return s.search(r) === 0;};
661
+ */
662
+
663
+ })();
664
+