已合并
[Bug]: 正则多行匹配时匹配\r作为结尾失败 #13688
hecunmao创建于 2025年12月10日
[Bug]: 正则多行匹配时匹配\r作为结尾失败 #13688
已合并
共 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_) { |
| 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: issue11945 | 20 | * @tc.require: issue11945 |
| 21 | */ | 21 | */ |
| 22 | { | 22 | { |
| 23 | - // Case 1: Global regex alternating between cache hits and misses | 23 | + // 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 again | 33 | + // 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 positions | 43 | + // 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 0 | 48 | + // 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 5 | 52 | + // Should fail at position 5 |
| 53 | - results.push(regex.test(str)); | 53 | + results.push(regex.test(str)); |
| 54 | - | 54 | + |
| 55 | - // Should succeed at position 12 | 55 | + // 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 state | 65 | + // 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=3 | 71 | + 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 | +} | ||
| 82 | test_end(); | 87 | test_end(); |
已检视,无问题