@@ -14,7 +14,7 @@ This proposal is part of a larger [regex-powered string processing initiative](h
1414
1515## Motivation
1616
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:
1818
1919``` swift
2020let 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
216216
217217```swift
218218let regex = Regex {
219- capture (. localizedCurreny (code : " USD" ))
219+ Capture (. localizedCurrency (code : " USD" ))
220220}
221221```
222-
222+
223223</ details>
224224
225225
@@ -234,7 +234,7 @@ extension Collection where Element: Equatable {
234234 /// - Parameter other: A sequence to search for within this collection.
235235 /// - Returns: `true` if the collection contains the specified sequence,
236236 /// otherwise `false`.
237- public func contains <S : Sequence >(_ other : S ) -> Bool
237+ public func contains <C : Collection >(_ other : C ) -> Bool
238238 where S.Element == Element
239239}
240240
@@ -244,7 +244,7 @@ extension BidirectionalCollection where SubSequence == Substring {
244244 /// - Parameter regex: A regex to search for within this collection.
245245 /// - Returns: `true` if the regex was found in the collection, otherwise
246246 /// `false`.
247- public func contains < R : RegexComponent > (_ regex : R ) -> Bool
247+ public func contains (_ regex : some RegexComponent ) -> Bool
248248}
249249```
250250
@@ -257,7 +257,7 @@ extension BidirectionalCollection where SubSequence == Substring {
257257 /// - Parameter regex: A regex to compare to this sequence.
258258 /// - Returns: `true` if the initial elements of the sequence matches the
259259 /// beginning of `regex`; otherwise, `false`.
260- public func starts < R : RegexComponent > (with regex : R ) -> Bool
260+ public func starts (with regex : some RegexComponent ) -> Bool
261261}
262262```
263263
@@ -281,7 +281,7 @@ extension Collection where SubSequence == Self {
281281 /// - Parameter predicate: A closure that takes an element of the sequence
282282 /// as its argument and returns a Boolean value indicating whether the
283283 /// 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
285285}
286286
287287extension RangeReplaceableCollection {
@@ -290,7 +290,7 @@ extension RangeReplaceableCollection {
290290 /// - Parameter predicate: A closure that takes an element of the sequence
291291 /// as its argument and returns a Boolean value indicating whether the
292292 /// 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
294294}
295295
296296extension Collection where Element : Equatable {
@@ -299,21 +299,21 @@ extension Collection where Element: Equatable {
299299 /// - Parameter prefix: The collection to remove from this collection.
300300 /// - Returns: A collection containing the elements that does not match
301301 /// `prefix` from the start.
302- public func trimmingPrefix <Prefix : Collection >(_ prefix : Prefix) -> SubSequence
302+ public func trimmingPrefix <Prefix : Sequence >(_ prefix : Prefix) -> SubSequence
303303 where Prefix.Element == Element
304304}
305305
306306extension Collection where SubSequence == Self , Element : Equatable {
307307 /// Removes the initial elements that matches `prefix` from the start.
308308 /// - 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)
310310 where Prefix.Element == Element
311311}
312312
313313extension RangeReplaceableCollection where Element : Equatable {
314314 /// Removes the initial elements that matches `prefix` from the start.
315315 /// - 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)
317317 where Prefix.Element == Element
318318}
319319
@@ -323,15 +323,15 @@ extension BidirectionalCollection where SubSequence == Substring {
323323 /// - Parameter regex: The regex to remove from this collection.
324324 /// - Returns: A new subsequence containing the elements of the collection
325325 /// 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
327327}
328328
329329extension RangeReplaceableCollection
330330 where Self : BidirectionalCollection , SubSequence == Substring
331331{
332332 /// Removes the initial elements that matches the given regex.
333333 /// - 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 )
335335}
336336```
337337
@@ -344,8 +344,8 @@ extension Collection where Element: Equatable {
344344 /// - Parameter sequence: The sequence to search for.
345345 /// - Returns: A range in the collection of the first occurrence of `sequence`.
346346 /// 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
349349}
350350
351351extension BidirectionalCollection where Element : Comparable {
@@ -354,8 +354,8 @@ extension BidirectionalCollection where Element: Comparable {
354354 /// - Parameter other: The sequence to search for.
355355 /// - Returns: A range in the collection of the first occurrence of `sequence`.
356356 /// 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
359359}
360360
361361extension BidirectionalCollection where SubSequence == Substring {
@@ -364,7 +364,7 @@ extension BidirectionalCollection where SubSequence == Substring {
364364 /// - Parameter regex: The regex to search for.
365365 /// - Returns: A range in the collection of the first occurrence of `regex`.
366366 /// 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 >?
368368}
369369```
370370
@@ -377,8 +377,8 @@ extension Collection where Element: Equatable {
377377 /// - Parameter other: The sequence to search for.
378378 /// - Returns: A collection of ranges of all occurrences of `other`. Returns
379379 /// 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
382382}
383383
384384extension BidirectionalCollection where SubSequence == Substring {
@@ -387,7 +387,7 @@ extension BidirectionalCollection where SubSequence == Substring {
387387 /// - Parameter regex: The regex to search for.
388388 /// - Returns: A collection or ranges in the receiver of all occurrences of
389389 /// `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 >>
391391}
392392```
393393
@@ -399,17 +399,17 @@ extension BidirectionalCollection where SubSequence == Substring {
399399 /// - Parameter regex: The regex to search for.
400400 /// - Returns: The first match of `regex` in the collection, or `nil` if
401401 /// 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 ?
403403
404404 /// Match a regex in its entirety.
405- /// - Parameter r : The regex to match against.
405+ /// - Parameter regex : The regex to match against.
406406 /// - 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?
408408
409409 /// 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.
411411 /// - 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?
413413}
414414```
415415
@@ -420,7 +420,7 @@ extension BidirectionalCollection where SubSequence == Substring {
420420 /// Returns a collection containing all matches of the specified regex.
421421 /// - Parameter regex: The regex to search for.
422422 /// - 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 >
424424}
425425```
426426
@@ -438,12 +438,12 @@ extension RangeReplaceableCollection where Element: Equatable {
438438 /// to replace. Default is `Int.max`.
439439 /// - Returns: A new collection in which all occurrences of `other` in
440440 /// `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 ,
443443 with replacement : Replacement,
444444 subrange : Range <Index >,
445445 maxReplacements : Int = .max
446- ) -> Self where S .Element == Element , Replacement.Element == Element
446+ ) -> Self where C .Element == Element , Replacement.Element == Element
447447
448448 /// Returns a new collection in which all occurrences of a target sequence
449449 /// are replaced by another collection.
@@ -454,23 +454,23 @@ extension RangeReplaceableCollection where Element: Equatable {
454454 /// to replace. Default is `Int.max`.
455455 /// - Returns: A new collection in which all occurrences of `other` in
456456 /// `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 ,
459459 with replacement : Replacement,
460460 maxReplacements : Int = .max
461- ) -> Self where S .Element == Element , Replacement.Element == Element
461+ ) -> Self where C .Element == Element , Replacement.Element == Element
462462
463463 /// Replaces all occurrences of a target sequence with a given collection
464464 /// - Parameters:
465465 /// - other: The sequence to replace.
466466 /// - replacement: The new elements to add to the collection.
467467 /// - maxReplacements: A number specifying how many occurrences of `other`
468468 /// 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 ,
471471 with replacement : Replacement,
472472 maxReplacements : Int = .max
473- ) where S .Element == Element , Replacement.Element == Element
473+ ) where C .Element == Element , Replacement.Element == Element
474474}
475475
476476extension RangeReplaceableCollection where SubSequence == Substring {
@@ -484,8 +484,8 @@ extension RangeReplaceableCollection where SubSequence == Substring {
484484 /// sequence matching `regex` to replace. Default is `Int.max`.
485485 /// - Returns: A new collection in which all occurrences of subsequence
486486 /// 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 ,
489489 with replacement : Replacement,
490490 subrange : Range <Index >,
491491 maxReplacements : Int = .max
@@ -500,8 +500,8 @@ extension RangeReplaceableCollection where SubSequence == Substring {
500500 /// sequence matching `regex` to replace. Default is `Int.max`.
501501 /// - Returns: A new collection in which all occurrences of subsequence
502502 /// 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 ,
505505 with replacement : Replacement,
506506 maxReplacements : Int = .max
507507 ) -> Self where Replacement.Element == Element
@@ -513,8 +513,8 @@ extension RangeReplaceableCollection where SubSequence == Substring {
513513 /// - replacement: The new elements to add to the collection.
514514 /// - maxReplacements: A number specifying how many occurrences of the
515515 /// 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 ,
518518 with replacement : Replacement,
519519 maxReplacements : Int = .max
520520 ) where Replacement.Element == Element
@@ -534,7 +534,7 @@ extension RangeReplaceableCollection where SubSequence == Substring {
534534 _ regex : R,
535535 subrange : Range <Index >,
536536 maxReplacements : Int = .max ,
537- with replacement : (RegexMatch <R.Match> ) throws -> Replacement
537+ with replacement : (Regex <R.RegexOutput>.Match ) throws -> Replacement
538538 ) rethrows -> Self where Replacement.Element == Element
539539
540540 /// Returns a new collection in which all occurrences of a sequence matching
@@ -550,7 +550,7 @@ extension RangeReplaceableCollection where SubSequence == Substring {
550550 public func replacing <R : RegexComponent , Replacement : Collection >(
551551 _ regex : R,
552552 maxReplacements : Int = .max ,
553- with replacement : (RegexMatch <R.Match> ) throws -> Replacement
553+ with replacement : (Regex <R.RegexOuput>.Match ) throws -> Replacement
554554 ) rethrows -> Self where Replacement.Element == Element
555555
556556 /// Replaces all occurrences of the sequence matching the given regex with
@@ -564,7 +564,7 @@ extension RangeReplaceableCollection where SubSequence == Substring {
564564 public mutating func replace <R : RegexComponent , Replacement : Collection >(
565565 _ regex : R,
566566 maxReplacements : Int = .max ,
567- with replacement : (RegexMatch <R.Match> ) throws -> Replacement
567+ with replacement : (Regex <R.RegexOutput>.Match ) throws -> Replacement
568568 ) rethrows where Replacement.Element == Element
569569}
570570```
@@ -574,27 +574,65 @@ extension RangeReplaceableCollection where SubSequence == Substring {
574574```swift
575575extension Collection where Element : Equatable {
576576 /// 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.
579588 /// - 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
583595}
584596
585597extension BidirectionalCollection where SubSequence == Substring {
586598 /// 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.
589609 /// - 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>
592616}
593617```
594618
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:
595620
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+ ```
596633
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
598636
599637## Alternatives considered
600638
0 commit comments