diff --git a/Sources/_StringProcessing/ByteCodeGen.swift b/Sources/_StringProcessing/ByteCodeGen.swift index 6a00a0df..90a47bdf 100644 --- a/Sources/_StringProcessing/ByteCodeGen.swift +++ b/Sources/_StringProcessing/ByteCodeGen.swift @@ -940,20 +940,26 @@ fileprivate extension Compiler.ByteCodeGen { case .atom(let atom): switch atom { case let .char(char): - characters.insert(char) + if characters.insert(char).inserted { + result.append(member) + } case let .scalar(scalar): - scalars.insert(scalar) + if scalars.insert(scalar).inserted { + result.append(member) + } default: result.append(member) } case let .quotedLiteral(str): - characters.formUnion(str) + for char in str { + if characters.insert(char).inserted { + result.append(.atom(.char(char))) + } + } default: result.append(member) } } - result.append(contentsOf: characters.map { .atom(.char($0)) }) - result.append(contentsOf: scalars.map { .atom(.scalar($0)) }) return result } diff --git a/Tests/RegexTests/MatchTests.swift b/Tests/RegexTests/MatchTests.swift index 017005e5..27302cda 100644 --- a/Tests/RegexTests/MatchTests.swift +++ b/Tests/RegexTests/MatchTests.swift @@ -2864,6 +2864,18 @@ extension RegexTests { XCTAssertNil(additionalInput.wholeMatch(of: additionalRegex)) } + func testIssueSwift81427() throws { + // This issue is a nondeterministic matching failure, where this character + // set is occasionally compiled incorrectly. Multiple test runs (not just + // multiple executions of this test) are required for verification. + firstMatchTests( + "[(?:\r\n)\n\r]", + ("\n", "\n"), + ("\r", "\r"), + ("\r\n", "\r\n") + ) + } + func testNSRECompatibility() throws { // NSRE-compatibility includes scalar matching, so `[\r\n]` should match // either `\r` or `\n`.