@@ -14,7 +14,7 @@ This proposal is part of a larger [regex-powered string processing initiative](h
14
14
15
15
## Motivation
16
16
17
- A number of common string processing APIs are missing from the Swift standard library. While most of the desired functionalities can be accomplished through a series of API calls, every gap adds a burden to developers doing frequent or complex string processing. For example, here's one approach to find the number of occurrences a substring ("banana") within a string:
17
+ A number of common string processing APIs are missing from the Swift standard library. While most of the desired functionalities can be accomplished through a series of API calls, every gap adds a burden to developers doing frequent or complex string processing. For example, here's one approach to find the number of occurrences of a substring ("banana") within a string:
18
18
19
19
``` swift
20
20
let str = " A banana a day keeps the doctor away. I love bananas; banana are my favorite fruit."
@@ -216,10 +216,10 @@ Matching and extracting a localized currency amount, such as `"$3,020.85"`, can
216
216
217
217
```swift
218
218
let regex = Regex {
219
- capture (. localizedCurreny (code : " USD" ))
219
+ Capture (. localizedCurrency (code : " USD" ))
220
220
}
221
221
```
222
-
222
+
223
223
</ details>
224
224
225
225
@@ -234,7 +234,7 @@ extension Collection where Element: Equatable {
234
234
/// - Parameter other: A sequence to search for within this collection.
235
235
/// - Returns: `true` if the collection contains the specified sequence,
236
236
/// otherwise `false`.
237
- public func contains <S : Sequence >(_ other : S ) -> Bool
237
+ public func contains <C : Collection >(_ other : C ) -> Bool
238
238
where S.Element == Element
239
239
}
240
240
@@ -244,7 +244,7 @@ extension BidirectionalCollection where SubSequence == Substring {
244
244
/// - Parameter regex: A regex to search for within this collection.
245
245
/// - Returns: `true` if the regex was found in the collection, otherwise
246
246
/// `false`.
247
- public func contains < R : RegexComponent > (_ regex : R ) -> Bool
247
+ public func contains (_ regex : some RegexComponent ) -> Bool
248
248
}
249
249
```
250
250
@@ -257,7 +257,7 @@ extension BidirectionalCollection where SubSequence == Substring {
257
257
/// - Parameter regex: A regex to compare to this sequence.
258
258
/// - Returns: `true` if the initial elements of the sequence matches the
259
259
/// beginning of `regex`; otherwise, `false`.
260
- public func starts < R : RegexComponent > (with regex : R ) -> Bool
260
+ public func starts (with regex : some RegexComponent ) -> Bool
261
261
}
262
262
```
263
263
@@ -281,7 +281,7 @@ extension Collection where SubSequence == Self {
281
281
/// - Parameter predicate: A closure that takes an element of the sequence
282
282
/// as its argument and returns a Boolean value indicating whether the
283
283
/// element should be removed from the collection.
284
- public mutating func trimPrefix (while predicate : (Element ) throws -> Bool )
284
+ public mutating func trimPrefix (while predicate : (Element ) throws -> Bool ) rethrows
285
285
}
286
286
287
287
extension RangeReplaceableCollection {
@@ -290,7 +290,7 @@ extension RangeReplaceableCollection {
290
290
/// - Parameter predicate: A closure that takes an element of the sequence
291
291
/// as its argument and returns a Boolean value indicating whether the
292
292
/// element should be removed from the collection.
293
- public mutating func trimPrefix (while predicate : (Element ) throws -> Bool )
293
+ public mutating func trimPrefix (while predicate : (Element ) throws -> Bool ) rethrows
294
294
}
295
295
296
296
extension Collection where Element : Equatable {
@@ -299,21 +299,21 @@ extension Collection where Element: Equatable {
299
299
/// - Parameter prefix: The collection to remove from this collection.
300
300
/// - Returns: A collection containing the elements that does not match
301
301
/// `prefix` from the start.
302
- public func trimmingPrefix <Prefix : Collection >(_ prefix : Prefix) -> SubSequence
302
+ public func trimmingPrefix <Prefix : Sequence >(_ prefix : Prefix) -> SubSequence
303
303
where Prefix.Element == Element
304
304
}
305
305
306
306
extension Collection where SubSequence == Self , Element : Equatable {
307
307
/// Removes the initial elements that matches `prefix` from the start.
308
308
/// - Parameter prefix: The collection to remove from this collection.
309
- public mutating func trimPrefix <Prefix : Collection >(_ prefix : Prefix)
309
+ public mutating func trimPrefix <Prefix : Sequence >(_ prefix : Prefix)
310
310
where Prefix.Element == Element
311
311
}
312
312
313
313
extension RangeReplaceableCollection where Element : Equatable {
314
314
/// Removes the initial elements that matches `prefix` from the start.
315
315
/// - Parameter prefix: The collection to remove from this collection.
316
- public mutating func trimPrefix <Prefix : Collection >(_ prefix : Prefix)
316
+ public mutating func trimPrefix <Prefix : Sequence >(_ prefix : Prefix)
317
317
where Prefix.Element == Element
318
318
}
319
319
@@ -323,15 +323,15 @@ extension BidirectionalCollection where SubSequence == Substring {
323
323
/// - Parameter regex: The regex to remove from this collection.
324
324
/// - Returns: A new subsequence containing the elements of the collection
325
325
/// that does not match `prefix` from the start.
326
- public func trimmingPrefix < R : RegexComponent > (_ regex : R ) -> SubSequence
326
+ public func trimmingPrefix (_ regex : some RegexComponent ) -> SubSequence
327
327
}
328
328
329
329
extension RangeReplaceableCollection
330
330
where Self : BidirectionalCollection , SubSequence == Substring
331
331
{
332
332
/// Removes the initial elements that matches the given regex.
333
333
/// - Parameter regex: The regex to remove from this collection.
334
- public mutating func trimPrefix < R : RegexComponent > (_ regex : R )
334
+ public mutating func trimPrefix (_ regex : some RegexComponent )
335
335
}
336
336
```
337
337
@@ -344,8 +344,8 @@ extension Collection where Element: Equatable {
344
344
/// - Parameter sequence: The sequence to search for.
345
345
/// - Returns: A range in the collection of the first occurrence of `sequence`.
346
346
/// Returns nil if `sequence` is not found.
347
- public func firstRange <S : Sequence >(of sequence : S ) -> Range <Index >?
348
- where S .Element == Element
347
+ public func firstRange <C : Collection >(of other : C ) -> Range <Index >?
348
+ where C .Element == Element
349
349
}
350
350
351
351
extension BidirectionalCollection where Element : Comparable {
@@ -354,8 +354,8 @@ extension BidirectionalCollection where Element: Comparable {
354
354
/// - Parameter other: The sequence to search for.
355
355
/// - Returns: A range in the collection of the first occurrence of `sequence`.
356
356
/// Returns `nil` if `sequence` is not found.
357
- public func firstRange <S : Sequence >(of other : S ) -> Range <Index >?
358
- where S .Element == Element
357
+ public func firstRange <C : BidirectionalCollection >(of other : C ) -> Range <Index >?
358
+ where C .Element == Element
359
359
}
360
360
361
361
extension BidirectionalCollection where SubSequence == Substring {
@@ -364,7 +364,7 @@ extension BidirectionalCollection where SubSequence == Substring {
364
364
/// - Parameter regex: The regex to search for.
365
365
/// - Returns: A range in the collection of the first occurrence of `regex`.
366
366
/// Returns `nil` if `regex` is not found.
367
- public func firstRange < R : RegexComponent > (of regex : R ) -> Range <Index >?
367
+ public func firstRange (of regex : some RegexComponent ) -> Range <Index >?
368
368
}
369
369
```
370
370
@@ -377,8 +377,8 @@ extension Collection where Element: Equatable {
377
377
/// - Parameter other: The sequence to search for.
378
378
/// - Returns: A collection of ranges of all occurrences of `other`. Returns
379
379
/// an empty collection if `other` is not found.
380
- public func ranges <S : Sequence >(of other : S ) -> some Collection <Range <Index >>
381
- where S .Element == Element
380
+ public func ranges <C : Collection >(of other : C ) -> some Collection <Range <Index >>
381
+ where C .Element == Element
382
382
}
383
383
384
384
extension BidirectionalCollection where SubSequence == Substring {
@@ -387,7 +387,7 @@ extension BidirectionalCollection where SubSequence == Substring {
387
387
/// - Parameter regex: The regex to search for.
388
388
/// - Returns: A collection or ranges in the receiver of all occurrences of
389
389
/// `regex`. Returns an empty collection if `regex` is not found.
390
- public func ranges < R : RegexComponent > (of regex : R ) -> some Collection <Range <Index >>
390
+ public func ranges (of regex : some RegexComponent ) -> some Collection <Range <Index >>
391
391
}
392
392
```
393
393
@@ -399,17 +399,17 @@ extension BidirectionalCollection where SubSequence == Substring {
399
399
/// - Parameter regex: The regex to search for.
400
400
/// - Returns: The first match of `regex` in the collection, or `nil` if
401
401
/// there isn't a match.
402
- public func firstMatch <R : RegexComponent >(of regex : R) -> RegexMatch <R.Match> ?
402
+ public func firstMatch <R : RegexComponent >(of regex : R) -> Regex <R.RegexOutput>.Match ?
403
403
404
404
/// Match a regex in its entirety.
405
- /// - Parameter r : The regex to match against.
405
+ /// - Parameter regex : The regex to match against.
406
406
/// - Returns: The match if there is one, or `nil` if none.
407
- public func wholeMatch <R : RegexComponent >(of r : R) -> Regex<R.Output >.Match?
407
+ public func wholeMatch <R : RegexComponent >(of regex : R) -> Regex<R.RegexOutput >.Match?
408
408
409
409
/// Match part of the regex, starting at the beginning.
410
- /// - Parameter r : The regex to match against.
410
+ /// - Parameter regex : The regex to match against.
411
411
/// - Returns: The match if there is one, or `nil` if none.
412
- public func prefixMatch <R : RegexComponent >(of r : R) -> Regex<R.Output >.Match?
412
+ public func prefixMatch <R : RegexComponent >(of regex : R) -> Regex<R.RegexOutput >.Match?
413
413
}
414
414
```
415
415
@@ -420,7 +420,7 @@ extension BidirectionalCollection where SubSequence == Substring {
420
420
/// Returns a collection containing all matches of the specified regex.
421
421
/// - Parameter regex: The regex to search for.
422
422
/// - Returns: A collection of matches of `regex`.
423
- public func matches <R : RegexComponent >(of regex : R) -> some Collection <RegexMatch <R.Match> >
423
+ public func matches <R : RegexComponent >(of regex : R) -> some Collection <Regex <R.RegexOuput>.Match >
424
424
}
425
425
```
426
426
@@ -438,12 +438,12 @@ extension RangeReplaceableCollection where Element: Equatable {
438
438
/// to replace. Default is `Int.max`.
439
439
/// - Returns: A new collection in which all occurrences of `other` in
440
440
/// `subrange` of the collection are replaced by `replacement`.
441
- public func replacing <S : Sequence , Replacement : Collection >(
442
- _ other : S ,
441
+ public func replacing <C : Collection , Replacement : Collection >(
442
+ _ other : C ,
443
443
with replacement : Replacement,
444
444
subrange : Range <Index >,
445
445
maxReplacements : Int = .max
446
- ) -> Self where S .Element == Element , Replacement.Element == Element
446
+ ) -> Self where C .Element == Element , Replacement.Element == Element
447
447
448
448
/// Returns a new collection in which all occurrences of a target sequence
449
449
/// are replaced by another collection.
@@ -454,23 +454,23 @@ extension RangeReplaceableCollection where Element: Equatable {
454
454
/// to replace. Default is `Int.max`.
455
455
/// - Returns: A new collection in which all occurrences of `other` in
456
456
/// `subrange` of the collection are replaced by `replacement`.
457
- public func replacing <S : Sequence , Replacement : Collection >(
458
- _ other : S ,
457
+ public func replacing <C : Collection , Replacement : Collection >(
458
+ _ other : C ,
459
459
with replacement : Replacement,
460
460
maxReplacements : Int = .max
461
- ) -> Self where S .Element == Element , Replacement.Element == Element
461
+ ) -> Self where C .Element == Element , Replacement.Element == Element
462
462
463
463
/// Replaces all occurrences of a target sequence with a given collection
464
464
/// - Parameters:
465
465
/// - other: The sequence to replace.
466
466
/// - replacement: The new elements to add to the collection.
467
467
/// - maxReplacements: A number specifying how many occurrences of `other`
468
468
/// to replace. Default is `Int.max`.
469
- public mutating func replace <S : Sequence , Replacement : Collection >(
470
- _ other : S ,
469
+ public mutating func replace <C : Collection , Replacement : Collection >(
470
+ _ other : C ,
471
471
with replacement : Replacement,
472
472
maxReplacements : Int = .max
473
- ) where S .Element == Element , Replacement.Element == Element
473
+ ) where C .Element == Element , Replacement.Element == Element
474
474
}
475
475
476
476
extension RangeReplaceableCollection where SubSequence == Substring {
@@ -484,8 +484,8 @@ extension RangeReplaceableCollection where SubSequence == Substring {
484
484
/// sequence matching `regex` to replace. Default is `Int.max`.
485
485
/// - Returns: A new collection in which all occurrences of subsequence
486
486
/// matching `regex` in `subrange` are replaced by `replacement`.
487
- public func replacing <R : RegexComponent , Replacement : Collection >(
488
- _ r : R ,
487
+ public func replacing <Replacement : Collection >(
488
+ _ r : some RegexComponent ,
489
489
with replacement : Replacement,
490
490
subrange : Range <Index >,
491
491
maxReplacements : Int = .max
@@ -500,8 +500,8 @@ extension RangeReplaceableCollection where SubSequence == Substring {
500
500
/// sequence matching `regex` to replace. Default is `Int.max`.
501
501
/// - Returns: A new collection in which all occurrences of subsequence
502
502
/// matching `regex` are replaced by `replacement`.
503
- public func replacing <R : RegexComponent , Replacement : Collection >(
504
- _ r : R ,
503
+ public func replacing <Replacement : Collection >(
504
+ _ r : some RegexComponent ,
505
505
with replacement : Replacement,
506
506
maxReplacements : Int = .max
507
507
) -> Self where Replacement.Element == Element
@@ -513,8 +513,8 @@ extension RangeReplaceableCollection where SubSequence == Substring {
513
513
/// - replacement: The new elements to add to the collection.
514
514
/// - maxReplacements: A number specifying how many occurrences of the
515
515
/// sequence matching `regex` to replace. Default is `Int.max`.
516
- public mutating func replace <R : RegexComponent , Replacement : Collection >(
517
- _ r : R ,
516
+ public mutating func replace <Replacement : Collection >(
517
+ _ r : some RegexComponent ,
518
518
with replacement : Replacement,
519
519
maxReplacements : Int = .max
520
520
) where Replacement.Element == Element
@@ -534,7 +534,7 @@ extension RangeReplaceableCollection where SubSequence == Substring {
534
534
_ regex : R,
535
535
subrange : Range <Index >,
536
536
maxReplacements : Int = .max ,
537
- with replacement : (RegexMatch <R.Match> ) throws -> Replacement
537
+ with replacement : (Regex <R.RegexOutput>.Match ) throws -> Replacement
538
538
) rethrows -> Self where Replacement.Element == Element
539
539
540
540
/// Returns a new collection in which all occurrences of a sequence matching
@@ -550,7 +550,7 @@ extension RangeReplaceableCollection where SubSequence == Substring {
550
550
public func replacing <R : RegexComponent , Replacement : Collection >(
551
551
_ regex : R,
552
552
maxReplacements : Int = .max ,
553
- with replacement : (RegexMatch <R.Match> ) throws -> Replacement
553
+ with replacement : (Regex <R.RegexOuput>.Match ) throws -> Replacement
554
554
) rethrows -> Self where Replacement.Element == Element
555
555
556
556
/// Replaces all occurrences of the sequence matching the given regex with
@@ -564,7 +564,7 @@ extension RangeReplaceableCollection where SubSequence == Substring {
564
564
public mutating func replace <R : RegexComponent , Replacement : Collection >(
565
565
_ regex : R,
566
566
maxReplacements : Int = .max ,
567
- with replacement : (RegexMatch <R.Match> ) throws -> Replacement
567
+ with replacement : (Regex <R.RegexOutput>.Match ) throws -> Replacement
568
568
) rethrows where Replacement.Element == Element
569
569
}
570
570
```
@@ -574,27 +574,65 @@ extension RangeReplaceableCollection where SubSequence == Substring {
574
574
```swift
575
575
extension Collection where Element : Equatable {
576
576
/// Returns the longest possible subsequences of the collection, in order,
577
- /// around elements equal to the given separator.
578
- /// - Parameter separator: The element to be split upon.
577
+ /// around elements equal to the given separator collection.
578
+ ///
579
+ /// - Parameters:
580
+ /// - separator: A collection of elements to be split upon.
581
+ /// - maxSplits: The maximum number of times to split the collection,
582
+ /// or one less than the number of subsequences to return.
583
+ /// - omittingEmptySubsequences: If `false`, an empty subsequence is
584
+ /// returned in the result for each consecutive pair of separator
585
+ /// sequences in the collection and for each instance of separator
586
+ /// sequences at the start or end of the collection. If `true`, only
587
+ /// nonempty subsequences are returned.
579
588
/// - Returns: A collection of subsequences, split from this collection's
580
- /// elements.
581
- public func split <S : Sequence >(by separator : S) -> some Collection <SubSequence >
582
- where S.Element == Element
589
+ /// elements.
590
+ public func split <C : Collection >(
591
+ separator : C,
592
+ maxSplits : Int = Int .max ,
593
+ omittingEmptySubsequences : Bool = true
594
+ ) -> some Collection <SubSequence > where C.Element == Element
583
595
}
584
596
585
597
extension BidirectionalCollection where SubSequence == Substring {
586
598
/// Returns the longest possible subsequences of the collection, in order,
587
- /// around elements equal to the given separator.
588
- /// - Parameter separator: A regex describing elements to be split upon.
599
+ /// around subsequence that match the given separator regex.
600
+ ///
601
+ /// - Parameters:
602
+ /// - separator: A regex to be split upon.
603
+ /// - maxSplits: The maximum number of times to split the collection,
604
+ /// or one less than the number of subsequences to return.
605
+ /// - omittingEmptySubsequences: If `false`, an empty subsequence is
606
+ /// returned in the result for each consecutive pair of matches
607
+ /// and for each match at the start or end of the collection. If
608
+ /// `true`, only nonempty subsequences are returned.
589
609
/// - Returns: A collection of substrings, split from this collection's
590
- /// elements.
591
- public func split <R : RegexComponent >(by separator : R) -> some Collection <Substring>
610
+ /// elements.
611
+ public func split (
612
+ separator : some RegexComponent,
613
+ maxSplits : Int = Int .max ,
614
+ omittingEmptySubsequences : Bool = true
615
+ ) -> some Collection <Substring>
592
616
}
593
617
```
594
618
619
+ ** Note: ** We plan to adopt the new generics features enabled by [SE- 0346 ][] for these proposed methods when the standard library adopts primary associated types, [pending a forthcoming proposal][stdlib- pitch]. For example, the first method in the _Replacement_ section above would instead be:
595
620
621
+ ```swift
622
+ extension RangeReplaceableCollection where Element : Equatable {
623
+ /// Returns a new collection in which all occurrences of a target sequence
624
+ /// are replaced by another collection.
625
+ public func replacing (
626
+ _ other : some Collection <Element >,
627
+ with replacement : some Collection <Element >,
628
+ subrange : Range <Index >,
629
+ maxReplacements : Int = .max
630
+ ) -> Self
631
+ }
632
+ ```
596
633
597
-
634
+ [SE- 0346 ]: https: // github.com/apple/swift-evolution/blob/main/proposals/0346-light-weight-same-type-syntax.md
635
+ [stdlib- pitch]: https: // forums.swift.org/t/pitch-primary-associated-types-in-the-standard-library/56426
598
636
599
637
## Alternatives considered
600
638
0 commit comments