1111//===----------------------------------------------------------------------===//
1212
1313extension String . Index {
14+ private init ? < S: StringProtocol > (
15+ _ sourcePosition: String . Index , _genericWithin target: S
16+ ) {
17+ guard target. _wholeGuts. isOnGraphemeClusterBoundary ( sourcePosition) else {
18+ return nil
19+ }
20+ self = sourcePosition
21+ }
22+
1423 /// Creates an index in the given string that corresponds exactly to the
1524 /// specified position.
1625 ///
@@ -49,14 +58,53 @@ extension String.Index {
4958 /// `sourcePosition` must be a valid index of at least one of the views
5059 /// of `target`.
5160 /// - target: The string referenced by the resulting index.
52- public init ? (
53- _ sourcePosition: String . Index ,
54- within target: String
61+ public init ? ( _ sourcePosition: String . Index , within target: String ) {
62+ self . init ( sourcePosition, _genericWithin: target)
63+ }
64+
65+ /// Creates an index in the given string that corresponds exactly to the
66+ /// specified position.
67+ ///
68+ /// If the index passed as `sourcePosition` represents the start of an
69+ /// extended grapheme cluster---the element type of a string---then the
70+ /// initializer succeeds.
71+ ///
72+ /// The following example converts the position of the Unicode scalar `"e"`
73+ /// into its corresponding position in the string. The character at that
74+ /// position is the composed `"é"` character.
75+ ///
76+ /// let cafe = "Cafe\u{0301}"
77+ /// print(cafe)
78+ /// // Prints "Café"
79+ ///
80+ /// let scalarsIndex = cafe.unicodeScalars.firstIndex(of: "e")!
81+ /// let stringIndex = String.Index(scalarsIndex, within: cafe)!
82+ ///
83+ /// print(cafe[...stringIndex])
84+ /// // Prints "Café"
85+ ///
86+ /// If the index passed as `sourcePosition` doesn't have an exact
87+ /// corresponding position in `target`, the result of the initializer is
88+ /// `nil`. For example, an attempt to convert the position of the combining
89+ /// acute accent (`"\u{0301}"`) fails. Combining Unicode scalars do not have
90+ /// their own position in a string.
91+ ///
92+ /// let nextScalarsIndex = cafe.unicodeScalars.index(after: scalarsIndex)
93+ /// let nextStringIndex = String.Index(nextScalarsIndex, within: cafe)
94+ ///
95+ /// print(nextStringIndex)
96+ /// // Prints "nil"
97+ ///
98+ /// - Parameters:
99+ /// - sourcePosition: A position in a view of the `target` parameter.
100+ /// `sourcePosition` must be a valid index of at least one of the views
101+ /// of `target`.
102+ /// - target: The string referenced by the resulting index.
103+ @available ( macOS 9999 , iOS 9999 , tvOS 9999 , watchOS 9999 , * )
104+ public init ? < S: StringProtocol > (
105+ _ sourcePosition: String . Index , within target: S
55106 ) {
56- guard target. _guts. isOnGraphemeClusterBoundary ( sourcePosition) else {
57- return nil
58- }
59- self = sourcePosition
107+ self . init ( sourcePosition, _genericWithin: target)
60108 }
61109
62110 /// Returns the position in the given UTF-8 view that corresponds exactly to
@@ -81,7 +129,7 @@ extension String.Index {
81129 /// position of a UTF-16 trailing surrogate returns `nil`.
82130 public func samePosition(
83131 in utf8: String . UTF8View
84- ) -> String . UTF8View . Index ? {
132+ ) -> String . UTF8View . Index ? {
85133 return String . UTF8View. Index ( self , within: utf8)
86134 }
87135
0 commit comments