已合并
[Bug]: 正则多行匹配时匹配\r作为结尾失败 #13688
[Bug]: 正则多行匹配时匹配\r作为结尾失败 #13688
已合并
hecunmao创建于 2025年12月10日
2 个文件变更+72-59
@@ -145,12 +145,16 @@ public:
145 145 
146 inline bool HandleOpLineStart(uint8_t opCode)146 inline bool HandleOpLineStart(uint8_t opCode)
147 {147 {
148- if ((GetCurrentPtr() == input_) ||148+ if (GetCurrentPtr() == input_) {
xwcai98
xwcai98xwcai982025年12月17日

已检视,无问题

likedislike
149- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
150- ((flags_ & RegExpParser::FLAG_MULTILINE) != 0 && PeekPrevChar(currentPtr_, input_) == '\n')) {
151 Advance(opCode);149 Advance(opCode);
150+ return true;
152 } else {151 } else {
153- if (MatchFailed()) {152+ uint32_t prevChar = PeekPrevChar(currentPtr_, input_);
153+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
154+ if ((flags_ & RegExpParser::FLAG_MULTILINE) != 0 && (prevChar == '\n' || prevChar == '\r')) {
155+ Advance(opCode);
156+ return true;
157+ } else if (MatchFailed()) {
154 return false;158 return false;
155 }159 }
156 }160 }
@@ -159,12 +163,16 @@ public:
159 163 
160 inline bool HandleOpLineEnd(uint8_t opCode)164 inline bool HandleOpLineEnd(uint8_t opCode)
161 {165 {
162- if (IsEOF() ||166+ if (IsEOF()) {
163- // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
164- ((flags_ & RegExpParser::FLAG_MULTILINE) != 0 && PeekChar(currentPtr_, inputEnd_) == '\n')) {
165 Advance(opCode);167 Advance(opCode);
168+ return true;
166 } else {169 } else {
167- if (MatchFailed()) {170+ uint32_t ch = PeekChar(currentPtr_, input_);
171+ // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
172+ if ((flags_ & RegExpParser::FLAG_MULTILINE) != 0 && (ch == '\n' || ch == '\r')) {
173+ Advance(opCode);
174+ return true;
175+ } else if (MatchFailed()) {
168 return false;176 return false;
169 }177 }
170 }178 }
@@ -20,63 +20,68 @@
20 * @tc.require: issue1194520 * @tc.require: issue11945
21 */21 */
22{22{
23- // Case 1: Global regex alternating between cache hits and misses23+ // Case 1: Global regex alternating between cache hits and misses
24- const regex = /\d+/g;24+ const regex = /\d+/g;
25- const results = [];25+ const results = [];
26- 26+
27- // First use - should hit cache (fresh state)27+ // First use - should hit cache (fresh state)
28- results.push(regex.test("abc123def"));28+ results.push(regex.test("abc123def"));
29- 29+
30- // Second use - should miss cache (lastIndex changed)30+ // Second use - should miss cache (lastIndex changed)
31- results.push(regex.test("abc123def"));31+ results.push(regex.test("abc123def"));
32- 32+
33- // Third use - reset and hit cache again33+ // Third use - reset and hit cache again
34- regex.lastIndex = 0;34+ regex.lastIndex = 0;
35- results.push(regex.test("abc123def"));35+ results.push(regex.test("abc123def"));
36- 36+
37- assert_equal(results[0], true);37+ assert_equal(results[0], true);
38- assert_equal(results[1], false);38+ assert_equal(results[1], false);
39- assert_equal(results[2], true);39+ assert_equal(results[2], true);
40}40}
41 41 
42{42{
43- // Case 2: Sticky flag with alternating positions43+ // Case 2: Sticky flag with alternating positions
44- const regex = /hello/y;44+ const regex = /hello/y;
45- const str = "hello world hello";45+ const str = "hello world hello";
46- const results = [];46+ const results = [];
47- 47+
48- // First match at position 048+ // First match at position 0
49- regex.lastIndex = 0;49+ regex.lastIndex = 0;
50- results.push(regex.test(str));50+ results.push(regex.test(str));
51- 51+
52- // Should fail at position 552+ // Should fail at position 5
53- results.push(regex.test(str));53+ results.push(regex.test(str));
54- 54+
55- // Should succeed at position 1255+ // Should succeed at position 12
56- regex.lastIndex = 12;56+ regex.lastIndex = 12;
57- results.push(regex.test(str));57+ results.push(regex.test(str));
58- 58+
59- assert_equal(results[0], true);59+ assert_equal(results[0], true);
60- assert_equal(results[1], false);60+ assert_equal(results[1], false);
61- assert_equal(results[2], true);61+ assert_equal(results[2], true);
62}62}
63 63 
64{64{
65- // Case 3: Multiple regex objects with same pattern but different state65+ // Case 3: Multiple regex objects with same pattern but different state
66- const regex1 = /\d+/g;66+ const regex1 = /\d+/g;
67- const regex2 = /\d+/g;67+ const regex2 = /\d+/g;
68- const str = "123 456";68+ const str = "123 456";
69- 69+
70- const results = [];70+ const results = [];
71- results.push(regex1.test(str)); // true, lastIndex=371+ results.push(regex1.test(str)); // true, lastIndex=3
72- results.push(regex2.test(str)); // true, lastIndex=3 (fresh regex)72+ results.push(regex2.test(str)); // true, lastIndex=3 (fresh regex)
73- results.push(regex1.test(str)); // true, lastIndex=7 (continues from 3)73+ results.push(regex1.test(str)); // true, lastIndex=7 (continues from 3)
74- results.push(regex2.test(str)); // true, lastIndex=7 (continues from 3)74+ results.push(regex2.test(str)); // true, lastIndex=7 (continues from 3)
75- 75+
76- assert_equal(results[0], true);76+ assert_equal(results[0], true);
77- assert_equal(results[1], true);77+ assert_equal(results[1], true);
78- assert_equal(results[2], true);78+ assert_equal(results[2], true);
79- assert_equal(results[3], true);79+ assert_equal(results[3], true);
80}80}
81 81 
82+{
83+ let reg = /^foo$/m;
84+ let res = reg.exec("\rfoo\r");
85+ assert_equal(res[0], "foo");
86+}
82test_end();87test_end();