Procházet zdrojové kódy

LibRegex: Do not continue searching input when the sticky bit is set

This partially reverts commit a962ee020a6310b2d7c7479aa058c15484127418.

When the sticky bit is set, the global bit should basically be ignored
except by external callers who want their own special behavior. For
example, RegExp.prototype [ @@match ] will use the global flag to
accumulate consecutive matches. But on the first failure, the regex
loop should break.
Timothy Flynn před 3 roky
rodič
revize
27d3de1f17

+ 8 - 0
Userland/Libraries/LibJS/Tests/builtins/String/String.prototype.match.js

@@ -70,3 +70,11 @@ test("escaped code points", () => {
     expect(string.match(re).groups.𝓑𝓻𝓸𝔀𝓷).toBe("brown");
     expect(string.match(re).groups.𝓑𝓻𝓸𝔀𝓷).toBe("brown");
 });
+
+test("sticky and global flag set", () => {
+    const string = "aaba";
+    expect(string.match(/a/)).toEqual(["a"]);
+    expect(string.match(/a/y)).toEqual(["a"]);
+    expect(string.match(/a/g)).toEqual(["a", "a", "a"]);
+    expect(string.match(/a/gy)).toEqual(["a", "a"]);
+});

+ 7 - 1
Userland/Libraries/LibRegex/RegexMatcher.cpp

@@ -180,6 +180,8 @@ RegexResult Matcher<Parser>::match(Vector<RegexStringView> const& views, Optiona
 #endif
 
     bool continue_search = input.regex_options.has_flag_set(AllFlags::Global) || input.regex_options.has_flag_set(AllFlags::Multiline);
+    if (input.regex_options.has_flag_set(AllFlags::Sticky))
+        continue_search = false;
 
     auto single_match_only = input.regex_options.has_flag_set(AllFlags::SingleMatch);
 
@@ -280,7 +282,11 @@ RegexResult Matcher<Parser>::match(Vector<RegexStringView> const& views, Optiona
                         break;
                     continue;
                 }
-                if (state.string_position < view_length && !input.regex_options.has_flag_set(AllFlags::Internal_Stateful)) {
+                if (input.regex_options.has_flag_set(AllFlags::Internal_Stateful)) {
+                    append_match(input, state, view_index);
+                    break;
+                }
+                if (state.string_position < view_length) {
                     return { false, 0, {}, {}, {}, operations };
                 }