C# improper result of index range expression
Asked Answered
D

3

6

I'm slightly confused with index range operator: I expected that the expression myString[..0] should be equvalent to myString[0..0], then myString.Substring(0, 1) or myString[0].ToString(), and in case of code below:

string myString = " abc";
string resultString = myString[..0];

the resultString value should be a single space " ". Unfortunately, I got String.Empty :(

Does anybody know why and can explain me, why I'm wrong?

The Microsoft docs doesn't describe similar cases (or I can't find them).

Delphina answered 26/2, 2022 at 17:18 Comment(2)
myString[0..0], then myString.Substring(0, 1) - careful; ranges take two indexes. Substring takes an index and a lengthBordy
I know that :) (I'm C# programmer for >15 last years) The topic was caused by my missunderstanding of range in C# - I expected that both indexes are inclusive.Delphina
P
7

the resultString value should be a single space " "

No, it shouldn't.

The end of a range is exclusive, not inclusive. So for example, x[0..x.Length] will always return the whole string.

In your case, you're saying "everything before index 0" which is obviously "the empty string".

This is documented in (aside from other places) the documentation for Range.End:

Gets an Index that represents the exclusive end index of the range.

Prehuman answered 26/2, 2022 at 17:31 Comment(3)
Lol, question was asked 12 minutes ago, and I managed to post my (similar) answer at the same time you post it. Anyhow thanksDew
Thanks. I was absolutely sure it was the opposite (both ends are inclusive).Delphina
"everything before" is the key to understanding the Range operator bounds.Miyamoto
B
6

It might be easier to consider the indexes in a range as being between the characters, not pointing to a character

enter image description here

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

enter image description here

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:

enter image description here

..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:

enter image description here

hw[^5..^1] //worl
hw[^5..10] //worl
hw[6..10]  //worl
hw[6..^1]  //worl
Bordy answered 26/2, 2022 at 18:38 Comment(2)
I can't agree with that: "indexes in a range as being between the characters", because the character pointed by the first index (start of range) will be included in result, but the character pointed by the second index (end of range) will NOT be included in result.Delphina
The indexes don't point TO the characters. They point to the line of pixels (let's say) BETWEEN the characters. Imagine you spray the phrase "hello_world" on 11 fence panels, then you hold them up with 12 fence posts, numbered 0 to 11.. the indexes are the fence posts, not the panels. It's the same thing as "the start is inclusive but the end is exclusive" but you don't have to remember the the -1 if you shift your perception of the indexes to the left a bitBordy
L
1

The .. is a syntax for System.Range and the form which you are using

string resultString = myString[..0];

is translated into,

string resultString = myString[Range.EndAt(new Index(0, fromEnd: true))] 

In your case, you are trying ..0 which means all elements which are before 0th index and that is the reason you are getting result as string.Empty

MSDN documentation for Index.End Property

Gets an Index that points beyond the last element.

Laocoon answered 26/2, 2022 at 17:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.