regexp.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113
  1. /*
  2. * Based on code from:
  3. *
  4. * XRegExp 1.5.0
  5. * (c) 2007-2010 Steven Levithan
  6. * MIT License
  7. * <http://xregexp.com>
  8. * Provides an augmented, extensible, cross-browser implementation of regular expressions,
  9. * including support for additional syntax, flags, and methods
  10. */
  11. define(function(require, exports, module) {
  12. "use strict";
  13. //---------------------------------
  14. // Private variables
  15. //---------------------------------
  16. var real = {
  17. exec: RegExp.prototype.exec,
  18. test: RegExp.prototype.test,
  19. match: String.prototype.match,
  20. replace: String.prototype.replace,
  21. split: String.prototype.split
  22. },
  23. compliantExecNpcg = real.exec.call(/()??/, "")[1] === undefined, // check `exec` handling of nonparticipating capturing groups
  24. compliantLastIndexIncrement = function () {
  25. var x = /^/g;
  26. real.test.call(x, "");
  27. return !x.lastIndex;
  28. }();
  29. if (compliantLastIndexIncrement && compliantExecNpcg)
  30. return;
  31. //---------------------------------
  32. // Overriden native methods
  33. //---------------------------------
  34. // Adds named capture support (with backreferences returned as `result.name`), and fixes two
  35. // cross-browser issues per ES3:
  36. // - Captured values for nonparticipating capturing groups should be returned as `undefined`,
  37. // rather than the empty string.
  38. // - `lastIndex` should not be incremented after zero-length matches.
  39. RegExp.prototype.exec = function (str) {
  40. var match = real.exec.apply(this, arguments),
  41. name, r2;
  42. if ( typeof(str) == 'string' && match) {
  43. // Fix browsers whose `exec` methods don't consistently return `undefined` for
  44. // nonparticipating capturing groups
  45. if (!compliantExecNpcg && match.length > 1 && indexOf(match, "") > -1) {
  46. r2 = RegExp(this.source, real.replace.call(getNativeFlags(this), "g", ""));
  47. // Using `str.slice(match.index)` rather than `match[0]` in case lookahead allowed
  48. // matching due to characters outside the match
  49. real.replace.call(str.slice(match.index), r2, function () {
  50. for (var i = 1; i < arguments.length - 2; i++) {
  51. if (arguments[i] === undefined)
  52. match[i] = undefined;
  53. }
  54. });
  55. }
  56. // Attach named capture properties
  57. if (this._xregexp && this._xregexp.captureNames) {
  58. for (var i = 1; i < match.length; i++) {
  59. name = this._xregexp.captureNames[i - 1];
  60. if (name)
  61. match[name] = match[i];
  62. }
  63. }
  64. // Fix browsers that increment `lastIndex` after zero-length matches
  65. if (!compliantLastIndexIncrement && this.global && !match[0].length && (this.lastIndex > match.index))
  66. this.lastIndex--;
  67. }
  68. return match;
  69. };
  70. // Don't override `test` if it won't change anything
  71. if (!compliantLastIndexIncrement) {
  72. // Fix browser bug in native method
  73. RegExp.prototype.test = function (str) {
  74. // Use the native `exec` to skip some processing overhead, even though the overriden
  75. // `exec` would take care of the `lastIndex` fix
  76. var match = real.exec.call(this, str);
  77. // Fix browsers that increment `lastIndex` after zero-length matches
  78. if (match && this.global && !match[0].length && (this.lastIndex > match.index))
  79. this.lastIndex--;
  80. return !!match;
  81. };
  82. }
  83. //---------------------------------
  84. // Private helper functions
  85. //---------------------------------
  86. function getNativeFlags (regex) {
  87. return (regex.global ? "g" : "") +
  88. (regex.ignoreCase ? "i" : "") +
  89. (regex.multiline ? "m" : "") +
  90. (regex.extended ? "x" : "") + // Proposed for ES4; included in AS3
  91. (regex.sticky ? "y" : "");
  92. }
  93. function indexOf (array, item, from) {
  94. if (Array.prototype.indexOf) // Use the native array method if available
  95. return array.indexOf(item, from);
  96. for (var i = from || 0; i < array.length; i++) {
  97. if (array[i] === item)
  98. return i;
  99. }
  100. return -1;
  101. }
  102. });