Skip to content

Commit fde4c58

Browse files
natecook1000Azoy
authored andcommitted
Add Substring algorithms tests (swiftlang#289)
`firstMatch(of:)` was ignoring the start/endIndex when searching in substrings; this change fixes that issue. Also adds the 'in' label to `Regex.firstMatch(in:Substring)` to match the rest of the related APIs.
1 parent ba032b6 commit fde4c58

File tree

3 files changed

+39
-12
lines changed

3 files changed

+39
-12
lines changed

Sources/_StringProcessing/Algorithms/Matching/FirstMatch.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,6 @@ extension BidirectionalCollection where SubSequence == Substring {
6161
of r: R
6262
) -> Regex<R.RegexOutput>.Match? {
6363
let slice = self[...]
64-
return try? r.regex.firstMatch(in: slice.base)
64+
return try? r.regex.firstMatch(in: slice)
6565
}
6666
}

Sources/_StringProcessing/Regex/Match.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ extension Regex {
123123
/// Find the first match in a substring
124124
///
125125
/// Returns `nil` if no match is found and throws on abort
126-
public func firstMatch(_ s: Substring) throws -> Regex<Output>.Match? {
126+
public func firstMatch(in s: Substring) throws -> Regex<Output>.Match? {
127127
try _firstMatch(s.base, in: s.startIndex..<s.endIndex)
128128
}
129129

Tests/RegexTests/AlgorithmsTests.swift

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,19 +34,11 @@ class RegexConsumerTests: XCTestCase {
3434
) {
3535
let regex = try! Regex(compiling: regex)
3636

37-
let actualSeq: [Range<Int>] = string[...].ranges(of: regex).map {
38-
let start = string.offset(ofIndex: $0.lowerBound)
39-
let end = string.offset(ofIndex: $0.upperBound)
40-
return start..<end
41-
}
37+
let actualSeq: [Range<Int>] = string[...].ranges(of: regex).map(string.offsets(of:))
4238
XCTAssertEqual(actualSeq, expected, file: file, line: line)
4339

4440
// `IndexingIterator` tests the collection conformance
45-
let actualCol: [Range<Int>] = string[...].ranges(of: regex)[...].map {
46-
let start = string.offset(ofIndex: $0.lowerBound)
47-
let end = string.offset(ofIndex: $0.upperBound)
48-
return start..<end
49-
}
41+
let actualCol: [Range<Int>] = string[...].ranges(of: regex)[...].map(string.offsets(of:))
5042
XCTAssertEqual(actualCol, expected, file: file, line: line)
5143
}
5244

@@ -145,4 +137,39 @@ class RegexConsumerTests: XCTestCase {
145137
XCTAssertEqual("x", "axb".trimming(r))
146138
XCTAssertEqual("x", "axbb".trimming(r))
147139
}
140+
141+
func testSubstring() throws {
142+
let s = "aaa | aaaaaa | aaaaaaaaaa"
143+
let s1 = s.dropFirst(6) // "aaaaaa | aaaaaaaaaa"
144+
let s2 = s1.dropLast(17) // "aa"
145+
let regex = try! Regex(compiling: "a+")
146+
147+
XCTAssertEqual(s.firstMatch(of: regex)?.0, "aaa")
148+
XCTAssertEqual(s1.firstMatch(of: regex)?.0, "aaaaaa")
149+
XCTAssertEqual(s2.firstMatch(of: regex)?.0, "aa")
150+
151+
XCTAssertEqual(
152+
s.ranges(of: regex).map(s.offsets(of:)),
153+
[0..<3, 6..<12, 15..<25])
154+
XCTAssertEqual(
155+
s1.ranges(of: regex).map(s.offsets(of:)),
156+
[6..<12, 15..<25])
157+
XCTAssertEqual(
158+
s2.ranges(of: regex).map(s.offsets(of:)),
159+
[6..<8])
160+
161+
XCTAssertEqual(s.replacing(regex, with: ""), " | | ")
162+
XCTAssertEqual(s1.replacing(regex, with: ""), " | ")
163+
XCTAssertEqual(s2.replacing(regex, with: ""), "")
164+
165+
XCTAssertEqual(
166+
s._matches(of: regex).map(\.0),
167+
["aaa", "aaaaaa", "aaaaaaaaaa"])
168+
XCTAssertEqual(
169+
s1._matches(of: regex).map(\.0),
170+
["aaaaaa", "aaaaaaaaaa"])
171+
XCTAssertEqual(
172+
s2._matches(of: regex).map(\.0),
173+
["aa"])
174+
}
148175
}

0 commit comments

Comments
 (0)