0

I'm trying to figure out why the following works on the first string cluster (character) but not on a second one. Perhaps the endIndex cannot be applied on another String?

let part = "A"
let full = "ABC"

print(full[part.startIndex ... part.startIndex])                    // "A"
print(full[part.endIndex ... part.endIndex])                        // ""   <- ???
print(full[part.endIndex ... full.index(after: part.endIndex)])     // "B"

bSecond should hold "B", but instead is empty. But the proof that one string index works on another is that the last statement works.

EDIT: Assuming full.hasPrefix(part) is true.

Swift puzzles.

jazzgil
  • 2,250
  • 2
  • 19
  • 20
  • 1
    Note that in most cases, you should never subscript a given collection with another collection's index. Although, there are some exceptions, such as with slices and collections with trivial indices, such as `Array`. – Hamish Feb 18 '17 at 12:12
  • 1
    Was about to write the same :) – With `let part = ""` your code will crash. – Martin R Feb 18 '17 at 12:13
  • Forgot to mention that. Assume full.hasPrefix(part)) is true... – jazzgil Feb 18 '17 at 15:16

1 Answers1

1

You cannot use the indices of one string to subscript a different string. That may work by chance (in your first example) or not (in your second example), or crash at runtime.

In this particular case, part.endIndex (which is the "one past the end position" for the part string) returns

String.UnicodeScalarView.Index(_position: 1), _countUTF16: 0)

with _countUTF16: (which is the "count of this extended grapheme cluster in UTF-16 code units") being zero, i.e. it describes a position (in the unicode scalar view) with no extent. Then

full[part.endIndex ... part.endIndex]

returns an empty string. But that is an implementation detail (compare StringCharacterView.swift). The real answer is just "you can't do that".

A safe way to obtain the intended (?) result is

let part = "A"
let full = "ABC"

if let range = full.range(of: part) {
    print(full[range]) // A
    if range.upperBound != full.endIndex {
        print(full[range.upperBound...range.upperBound]) // B
    }
}
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • Thanks @Martin, your answer is useful, but it doesn't answer why part.endIndex works in index/after but not in subscript upper range. – jazzgil Feb 18 '17 at 15:05