Swift has very sane way of doing this: Strings are sequences of Characters.  Characters represent extended grapheme clusters.  Iteration consumes as many bytes from the string as are necessary to read the next grapheme.  In most cases, this is straight-up UTF-8 decoding, which can be implemented very efficiently; you only need to worry about extended grapheme clusters when you get to the non-ASCII subset of Unicode, so the code paths that require unicode table lookups are infrequently exercised.<p>String searching &amp; matching return an opaque String.Index type.  I assume that under the hood they do Boyer-Moore on bytes and String.Index is a byte offset, but the important thing is that String.Index values are not convertible to integers, and so you never run into the case where a user passes in a byte offset that would slice a grapheme in half.  Instead, String.Index has properties for the next and previous index and a method to advance by an arbitrary amount, so you&#x27;d access the 7th character after a dash in a string as myString[myString.rangeOfString(&quot;-&quot;).advanceBy(7)]<p>Swift gives up on the idea that len(x+y) = len(x) + len(y).  This is just something you have to remember; in UI programming, however, it makes a lot of sense because adding an accent to an existing string isn&#x27;t going to make it take up more width in the text box.  (x + y).utf8.count == x.utf8.count + y.utf8.count, however.<p><a href="https:&#x2F;&#x2F;developer.apple.com&#x2F;library&#x2F;ios&#x2F;documentation&#x2F;Swift&#x2F;Conceptual&#x2F;Swift_Programming_Language&#x2F;StringsAndCharacters.html" rel="nofollow">https:&#x2F;&#x2F;developer.apple.com&#x2F;library&#x2F;ios&#x2F;documentation&#x2F;Swift&#x2F;...</a><p>If I were to adapt this to a domain like Python&#x27;s, where string processing is pretty important, I&#x27;d allow indexing &amp; slicing by integers (including negative integers), but I&#x27;d define them in terms of String.Index types, which iterate over extended graphemes under the hood:<p><pre><code>  str[2] == str[str.start.advanceBy(2)]
  str[-3] == str[str.end.advanceBy(-3)]
  str[str.find(&#x27;foo&#x27;) + 3] == str[str.find(&#x27;foo&#x27;).advanceBy(3)]
  str[0:-3] == str.substring(str.start, str.end.advanceBy(-3))
  del str[0:3] == str.removeRange(str.start, str.start.advanceBy(3))</code></pre>