It might be easier to consider the indexes in a range as being between the characters, not pointing to a character
If the characters in the string were sprayed on fence panels, then the indexes in a range refer to the fence posts, not the fence panels
When you cut a string with ranges you get all the chars between the indexes. When you uproot fence posts from X to Y, the fence panels between the posts fall down - you get the characters on the fallen panels
var hw = "Hello world";
hw[0..11] //Hello world
hw[..5] //Hello
hw[0..0] //(empty string - there are no characters between index 0 and index 0)
The reason I recommend to think about indexes in a range as between characters is it makes using the "from the right" indexer ^n
easy to reason about. Taking [^7..^2]
will take these panels:
..so you get o wor
If you were to think of the indexes as pointing to characters or to panels then then have to remember a) "the end of the range is exclusive" and then also b) that there's an imaginary character added onto the end of the string that is ^0
, just so you can exclude it again. Or you have to think "the ^x indexes are from the right, and if you use them it flips the exclusive around", and then you have to come up with some way of remembering or working out which is the exclusive end if you're mixing non-^
indexes with ^
indexes.
All in, it's most consistent to just remember "the indexes are between the characters" and "^ is from the right" then you can mix and match whatever you like:
hw[^5..^1] //worl
hw[^5..10] //worl
hw[6..10] //worl
hw[6..^1] //worl
myString[0..0], then myString.Substring(0, 1)
- careful; ranges take two indexes. Substring takes an index and a length – Bordy