Skip to content

Commit b24d3ea

Browse files
authored
Move the closure argument to the end of the arg list (#307)
Move the closure argument in `replace` and `replacing` to the end of the argument list for trailing closure syntax. Add a test for replacing within a range.
1 parent 46b9a0f commit b24d3ea

File tree

3 files changed

+72
-28
lines changed

3 files changed

+72
-28
lines changed

Documentation/Evolution/StringProcessingAlgorithms.md

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -511,48 +511,48 @@ extension RangeReplaceableCollection where SubSequence == Substring {
511511
/// the given regex are replaced by another regex match.
512512
/// - Parameters:
513513
/// - regex: A regex describing the sequence to replace.
514-
/// - replacement: A closure that receives the full match information,
515-
/// including captures, and returns a replacement collection.
516514
/// - subrange: The range in the collection in which to search for `regex`.
517515
/// - maxReplacements: A number specifying how many occurrences of the
518516
/// sequence matching `regex` to replace. Default is `Int.max`.
517+
/// - replacement: A closure that receives the full match information,
518+
/// including captures, and returns a replacement collection.
519519
/// - Returns: A new collection in which all occurrences of subsequence
520520
/// matching `regex` are replaced by `replacement`.
521521
public func replacing<R: RegexComponent, Replacement: Collection>(
522522
_ regex: R,
523-
with replacement: (RegexMatch<R.Match>) throws -> Replacement,
524523
subrange: Range<Index>,
525-
maxReplacements: Int = .max
524+
maxReplacements: Int = .max,
525+
with replacement: (RegexMatch<R.Match>) throws -> Replacement
526526
) rethrows -> Self where Replacement.Element == Element
527527

528528
/// Returns a new collection in which all occurrences of a sequence matching
529529
/// the given regex are replaced by another collection.
530530
/// - Parameters:
531531
/// - regex: A regex describing the sequence to replace.
532-
/// - replacement: A closure that receives the full match information,
533-
/// including captures, and returns a replacement collection.
534532
/// - maxReplacements: A number specifying how many occurrences of the
535533
/// sequence matching `regex` to replace. Default is `Int.max`.
534+
/// - replacement: A closure that receives the full match information,
535+
/// including captures, and returns a replacement collection.
536536
/// - Returns: A new collection in which all occurrences of subsequence
537537
/// matching `regex` are replaced by `replacement`.
538538
public func replacing<R: RegexComponent, Replacement: Collection>(
539539
_ regex: R,
540-
with replacement: (RegexMatch<R.Match>) throws -> Replacement,
541-
maxReplacements: Int = .max
540+
maxReplacements: Int = .max,
541+
with replacement: (RegexMatch<R.Match>) throws -> Replacement
542542
) rethrows -> Self where Replacement.Element == Element
543543

544544
/// Replaces all occurrences of the sequence matching the given regex with
545545
/// a given collection.
546546
/// - Parameters:
547547
/// - regex: A regex describing the sequence to replace.
548-
/// - replacement: A closure that receives the full match information,
549-
/// including captures, and returns a replacement collection.
550548
/// - maxReplacements: A number specifying how many occurrences of the
551549
/// sequence matching `regex` to replace. Default is `Int.max`.
550+
/// - replacement: A closure that receives the full match information,
551+
/// including captures, and returns a replacement collection.
552552
public mutating func replace<R: RegexComponent, Replacement: Collection>(
553553
_ regex: R,
554-
with replacement: (RegexMatch<R.Match>) throws -> Replacement,
555-
maxReplacements: Int = .max
554+
maxReplacements: Int = .max,
555+
with replacement: (RegexMatch<R.Match>) throws -> Replacement
556556
) rethrows where Replacement.Element == Element
557557
}
558558
```

Sources/_StringProcessing/Algorithms/Matching/MatchReplace.swift

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -118,19 +118,19 @@ extension RangeReplaceableCollection where SubSequence == Substring {
118118
/// the given regex are replaced by another regex match.
119119
/// - Parameters:
120120
/// - regex: A regex describing the sequence to replace.
121-
/// - replacement: A closure that receives the full match information,
122-
/// including captures, and returns a replacement collection.
123121
/// - subrange: The range in the collection in which to search for `regex`.
124122
/// - maxReplacements: A number specifying how many occurrences of the
125123
/// sequence matching `regex` to replace. Default is `Int.max`.
124+
/// - replacement: A closure that receives the full match information,
125+
/// including captures, and returns a replacement collection.
126126
/// - Returns: A new collection in which all occurrences of subsequence
127127
/// matching `regex` are replaced by `replacement`.
128128
@available(SwiftStdlib 5.7, *)
129129
public func replacing<R: RegexComponent, Replacement: Collection>(
130130
_ regex: R,
131-
with replacement: (Regex<R.RegexOutput>.Match) throws -> Replacement,
132131
subrange: Range<Index>,
133-
maxReplacements: Int = .max
132+
maxReplacements: Int = .max,
133+
with replacement: (Regex<R.RegexOutput>.Match) throws -> Replacement
134134
) rethrows -> Self where Replacement.Element == Element {
135135

136136
precondition(maxReplacements >= 0)
@@ -155,43 +155,43 @@ extension RangeReplaceableCollection where SubSequence == Substring {
155155
/// the given regex are replaced by another collection.
156156
/// - Parameters:
157157
/// - regex: A regex describing the sequence to replace.
158-
/// - replacement: A closure that receives the full match information,
159-
/// including captures, and returns a replacement collection.
160158
/// - maxReplacements: A number specifying how many occurrences of the
161159
/// sequence matching `regex` to replace. Default is `Int.max`.
160+
/// - replacement: A closure that receives the full match information,
161+
/// including captures, and returns a replacement collection.
162162
/// - Returns: A new collection in which all occurrences of subsequence
163163
/// matching `regex` are replaced by `replacement`.
164164
@available(SwiftStdlib 5.7, *)
165165
public func replacing<R: RegexComponent, Replacement: Collection>(
166166
_ regex: R,
167-
with replacement: (Regex<R.RegexOutput>.Match) throws -> Replacement,
168-
maxReplacements: Int = .max
167+
maxReplacements: Int = .max,
168+
with replacement: (Regex<R.RegexOutput>.Match) throws -> Replacement
169169
) rethrows -> Self where Replacement.Element == Element {
170170
try replacing(
171171
regex,
172-
with: replacement,
173172
subrange: startIndex..<endIndex,
174-
maxReplacements: maxReplacements)
173+
maxReplacements: maxReplacements,
174+
with: replacement)
175175
}
176176

177177
/// Replaces all occurrences of the sequence matching the given regex with
178178
/// a given collection.
179179
/// - Parameters:
180180
/// - regex: A regex describing the sequence to replace.
181-
/// - replacement: A closure that receives the full match information,
182-
/// including captures, and returns a replacement collection.
183181
/// - maxReplacements: A number specifying how many occurrences of the
184182
/// sequence matching `regex` to replace. Default is `Int.max`.
183+
/// - replacement: A closure that receives the full match information,
184+
/// including captures, and returns a replacement collection.
185185
@available(SwiftStdlib 5.7, *)
186186
public mutating func replace<R: RegexComponent, Replacement: Collection>(
187187
_ regex: R,
188-
with replacement: (Regex<R.RegexOutput>.Match) throws -> Replacement,
189-
maxReplacements: Int = .max
188+
maxReplacements: Int = .max,
189+
with replacement: (Regex<R.RegexOutput>.Match) throws -> Replacement
190190
) rethrows where Replacement.Element == Element {
191191
self = try replacing(
192192
regex,
193-
with: replacement,
194193
subrange: startIndex..<endIndex,
195-
maxReplacements: maxReplacements)
194+
maxReplacements: maxReplacements,
195+
with: replacement)
196196
}
197197
}

Tests/RegexBuilderTests/AlgorithmsTests.swift

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,48 @@ class RegexConsumerTests: XCTestCase {
6060
result: "6 60 0 6x4",
6161
{ match in "\(match.output.1 * match.output.2 * (match.output.3 ?? 1))" })
6262
}
63+
64+
func testMatchReplaceSubrange() {
65+
func replaceTest<R: RegexComponent>(
66+
_ regex: R,
67+
input: String,
68+
_ replace: (Regex<R.RegexOutput>.Match) -> String,
69+
_ tests: (subrange: Range<String.Index>, maxReplacement: Int, result: String)...,
70+
file: StaticString = #file,
71+
line: UInt = #line
72+
) {
73+
for (subrange, maxReplacement, result) in tests {
74+
XCTAssertEqual(input.replacing(regex, subrange: subrange, maxReplacements: maxReplacement, with: replace), result, file: file, line: line)
75+
}
76+
}
77+
78+
let int = Capture(OneOrMore(.digit)) { Int($0)! }
79+
80+
let addition = "9+16, 0+3, 5+5, 99+1"
81+
82+
replaceTest(
83+
Regex { int; "+"; int },
84+
input: "9+16, 0+3, 5+5, 99+1",
85+
{ match in "\(match.output.1 + match.output.2)" },
86+
87+
(subrange: addition.startIndex..<addition.endIndex,
88+
maxReplacement: 0,
89+
result: "9+16, 0+3, 5+5, 99+1"),
90+
(subrange: addition.startIndex..<addition.endIndex,
91+
maxReplacement: .max,
92+
result: "25, 3, 10, 100"),
93+
(subrange: addition.startIndex..<addition.endIndex,
94+
maxReplacement: 2,
95+
result: "25, 3, 5+5, 99+1"),
96+
(subrange: addition.index(addition.startIndex, offsetBy: 5) ..< addition.endIndex,
97+
maxReplacement: .max,
98+
result: "9+16, 3, 10, 100"),
99+
(subrange: addition.startIndex ..< addition.index(addition.startIndex, offsetBy: 5),
100+
maxReplacement: .max,
101+
result: "25, 0+3, 5+5, 99+1"),
102+
(subrange: addition.index(addition.startIndex, offsetBy: 5) ..< addition.endIndex,
103+
maxReplacement: 2,
104+
result: "9+16, 3, 10, 99+1")
105+
)
106+
}
63107
}

0 commit comments

Comments
 (0)