regexp-exec.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. 'use strict';
  2. /* eslint-disable regexp/no-empty-capturing-group, regexp/no-empty-group, regexp/no-lazy-ends -- testing */
  3. /* eslint-disable regexp/no-useless-quantifier -- testing */
  4. var call = require('../internals/function-call');
  5. var uncurryThis = require('../internals/function-uncurry-this');
  6. var toString = require('../internals/to-string');
  7. var regexpFlags = require('../internals/regexp-flags');
  8. var stickyHelpers = require('../internals/regexp-sticky-helpers');
  9. var shared = require('../internals/shared');
  10. var create = require('../internals/object-create');
  11. var getInternalState = require('../internals/internal-state').get;
  12. var UNSUPPORTED_DOT_ALL = require('../internals/regexp-unsupported-dot-all');
  13. var UNSUPPORTED_NCG = require('../internals/regexp-unsupported-ncg');
  14. var nativeReplace = shared('native-string-replace', String.prototype.replace);
  15. var nativeExec = RegExp.prototype.exec;
  16. var patchedExec = nativeExec;
  17. var charAt = uncurryThis(''.charAt);
  18. var indexOf = uncurryThis(''.indexOf);
  19. var replace = uncurryThis(''.replace);
  20. var stringSlice = uncurryThis(''.slice);
  21. var UPDATES_LAST_INDEX_WRONG = (function () {
  22. var re1 = /a/;
  23. var re2 = /b*/g;
  24. call(nativeExec, re1, 'a');
  25. call(nativeExec, re2, 'a');
  26. return re1.lastIndex !== 0 || re2.lastIndex !== 0;
  27. })();
  28. var UNSUPPORTED_Y = stickyHelpers.BROKEN_CARET;
  29. // nonparticipating capturing group, copied from es5-shim's String#split patch.
  30. var NPCG_INCLUDED = /()??/.exec('')[1] !== undefined;
  31. var PATCH = UPDATES_LAST_INDEX_WRONG || NPCG_INCLUDED || UNSUPPORTED_Y || UNSUPPORTED_DOT_ALL || UNSUPPORTED_NCG;
  32. var setGroups = function (re, groups) {
  33. var object = re.groups = create(null);
  34. for (var i = 0; i < groups.length; i++) {
  35. var group = groups[i];
  36. object[group[0]] = re[group[1]];
  37. }
  38. };
  39. if (PATCH) {
  40. patchedExec = function exec(string) {
  41. var re = this;
  42. var state = getInternalState(re);
  43. var str = toString(string);
  44. var raw = state.raw;
  45. var result, reCopy, lastIndex;
  46. if (raw) {
  47. raw.lastIndex = re.lastIndex;
  48. result = call(patchedExec, raw, str);
  49. re.lastIndex = raw.lastIndex;
  50. if (result && state.groups) setGroups(result, state.groups);
  51. return result;
  52. }
  53. var groups = state.groups;
  54. var sticky = UNSUPPORTED_Y && re.sticky;
  55. var flags = call(regexpFlags, re);
  56. var source = re.source;
  57. var charsAdded = 0;
  58. var strCopy = str;
  59. if (sticky) {
  60. flags = replace(flags, 'y', '');
  61. if (indexOf(flags, 'g') === -1) {
  62. flags += 'g';
  63. }
  64. strCopy = stringSlice(str, re.lastIndex);
  65. // Support anchored sticky behavior.
  66. var prevChar = re.lastIndex > 0 && charAt(str, re.lastIndex - 1);
  67. if (re.lastIndex > 0 &&
  68. (!re.multiline || re.multiline && prevChar !== '\n' && prevChar !== '\r' && prevChar !== '\u2028' && prevChar !== '\u2029')) {
  69. source = '(?: (?:' + source + '))';
  70. strCopy = ' ' + strCopy;
  71. charsAdded++;
  72. }
  73. // ^(? + rx + ) is needed, in combination with some str slicing, to
  74. // simulate the 'y' flag.
  75. reCopy = new RegExp('^(?:' + source + ')', flags);
  76. }
  77. if (NPCG_INCLUDED) {
  78. reCopy = new RegExp('^' + source + '$(?!\\s)', flags);
  79. }
  80. if (UPDATES_LAST_INDEX_WRONG) lastIndex = re.lastIndex;
  81. var match = call(nativeExec, sticky ? reCopy : re, strCopy);
  82. if (sticky) {
  83. if (match) {
  84. match.input = str;
  85. match[0] = stringSlice(match[0], charsAdded);
  86. match.index = re.lastIndex;
  87. re.lastIndex += match[0].length;
  88. } else re.lastIndex = 0;
  89. } else if (UPDATES_LAST_INDEX_WRONG && match) {
  90. re.lastIndex = re.global ? match.index + match[0].length : lastIndex;
  91. }
  92. if (NPCG_INCLUDED && match && match.length > 1) {
  93. // Fix browsers whose `exec` methods don't consistently return `undefined`
  94. // for NPCG, like IE8. NOTE: This doesn't work for /(.?)?/
  95. call(nativeReplace, match[0], reCopy, function () {
  96. for (var i = 1; i < arguments.length - 2; i++) {
  97. if (arguments[i] === undefined) match[i] = undefined;
  98. }
  99. });
  100. }
  101. if (match && groups) setGroups(match, groups);
  102. return match;
  103. };
  104. }
  105. module.exports = patchedExec;