diff --git a/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift b/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift index a4dce19b7..cb527f948 100644 --- a/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift +++ b/Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift @@ -61,6 +61,6 @@ extension BidirectionalCollection where SubSequence == Substring { of r: R ) -> Regex.Match? { let slice = self[...] - return try? r.regex.firstMatch(in: slice.base) + return try? r.regex.firstMatch(in: slice) } } diff --git a/Sources/_StringProcessing/Regex/Match.swift b/Sources/_StringProcessing/Regex/Match.swift index 251febc87..a86899041 100644 --- a/Sources/_StringProcessing/Regex/Match.swift +++ b/Sources/_StringProcessing/Regex/Match.swift @@ -123,7 +123,7 @@ extension Regex { /// Find the first match in a substring /// /// Returns `nil` if no match is found and throws on abort - public func firstMatch(_ s: Substring) throws -> Regex.Match? { + public func firstMatch(in s: Substring) throws -> Regex.Match? { try _firstMatch(s.base, in: s.startIndex..] = string[...].ranges(of: regex).map { - let start = string.offset(ofIndex: $0.lowerBound) - let end = string.offset(ofIndex: $0.upperBound) - return start..] = string[...].ranges(of: regex).map(string.offsets(of:)) XCTAssertEqual(actualSeq, expected, file: file, line: line) // `IndexingIterator` tests the collection conformance - let actualCol: [Range] = string[...].ranges(of: regex)[...].map { - let start = string.offset(ofIndex: $0.lowerBound) - let end = string.offset(ofIndex: $0.upperBound) - return start..] = string[...].ranges(of: regex)[...].map(string.offsets(of:)) XCTAssertEqual(actualCol, expected, file: file, line: line) } @@ -145,4 +137,39 @@ class RegexConsumerTests: XCTestCase { XCTAssertEqual("x", "axb".trimming(r)) XCTAssertEqual("x", "axbb".trimming(r)) } + + func testSubstring() throws { + let s = "aaa | aaaaaa | aaaaaaaaaa" + let s1 = s.dropFirst(6) // "aaaaaa | aaaaaaaaaa" + let s2 = s1.dropLast(17) // "aa" + let regex = try! Regex(compiling: "a+") + + XCTAssertEqual(s.firstMatch(of: regex)?.0, "aaa") + XCTAssertEqual(s1.firstMatch(of: regex)?.0, "aaaaaa") + XCTAssertEqual(s2.firstMatch(of: regex)?.0, "aa") + + XCTAssertEqual( + s.ranges(of: regex).map(s.offsets(of:)), + [0..<3, 6..<12, 15..<25]) + XCTAssertEqual( + s1.ranges(of: regex).map(s.offsets(of:)), + [6..<12, 15..<25]) + XCTAssertEqual( + s2.ranges(of: regex).map(s.offsets(of:)), + [6..<8]) + + XCTAssertEqual(s.replacing(regex, with: ""), " | | ") + XCTAssertEqual(s1.replacing(regex, with: ""), " | ") + XCTAssertEqual(s2.replacing(regex, with: ""), "") + + XCTAssertEqual( + s._matches(of: regex).map(\.0), + ["aaa", "aaaaaa", "aaaaaaaaaa"]) + XCTAssertEqual( + s1._matches(of: regex).map(\.0), + ["aaaaaa", "aaaaaaaaaa"]) + XCTAssertEqual( + s2._matches(of: regex).map(\.0), + ["aa"]) + } }