sharp que historia ejemplos c# .net string substring clr

que - string[] c#



Comportamiento inesperado de la subcadena en C# (8)

Esta pregunta ya tiene una respuesta aquí:

La definición del método Substring() en la clase .net System.String es como esta

public string Substring(int startIndex)

Donde startIndex es "La posición de carácter de inicio basada en cero de una subcadena en esta instancia" según la definición del método. Si lo entiendo correctamente, significa que me dará una parte de la cadena, comenzando en el índice de base cero dado.

Ahora, si tengo una cadena "ABC" y tomo una subcadena con diferentes índices, obtengo los siguientes resultados.

var str = "ABC"; var chars = str.ToArray(); //returns 3 char ''A'', ''B'', ''C'' as expected var sub2 = str.Substring(2); //[1] returns "C" as expected var sub3 = str.Substring(3); //[2] returns "" ...!!! Why no exception?? var sub4 = str.Substring(4); //[3] throws ArgumentOutOfRangeException as expected

¿Por qué no lanza excepción para el caso [2]?

La cadena tiene 3 caracteres, por lo que los índices son [0, 1, 2] , e incluso ToArray() , el método ToCharArray() devuelve 3 caracteres como se esperaba. ¿No debería lanzar una excepción si trato de Substring() con el índice de inicio 3 ?


Aquí hay muchas respuestas técnicas que dicen cómo el marco maneja la llamada al método, pero me gustaría dar un razonamiento por analogía de por qué es así.

Considere la string como una cerca donde los paneles de la cerca son los personajes, sostenidos con postes de la cerca numerados como se muestra a continuación:

0 1 2 3 | A | B | C | "ABC" 0 1 2 3 4 5 6 7 8 9 | M | y | | S | t | r | i | n | g | "My String"

En esta analogía, string.Substring(n) devuelve una string de paneles que comienza con fencepost n . Observe que el último carácter de la cadena tiene una publicación de cerca después de ella. Llamar a la función con esta publicación de valla devuelve un valor que indica que no hay paneles de valla después de este punto (es decir, devuelve la string vacía).

De forma similar, string.Substring(n, l) devuelve una string de l paneles que comienzan con fencepost n . Es por esto que algo como "ABC".Substring(2, 0) devuelve "" .


Basado en lo que está escrito en MSDN:

*

Valor de retorno : una cadena que es equivalente a la subcadena que comienza en startIndex en esta instancia, o Vacía si startIndex es igual a la longitud de esta instancia.

Excepciones ArgumentOutOfRangeException - startIndex es menor que cero o mayor que la longitud de esta instancia

*


En cuanto a la documentación del método String.Substring , se devolverá una cadena vacía si el índice de inicio es igual a la longitud.

Una cadena que es equivalente a la subcadena de longitud de longitud que comienza en startIndex en esta instancia, o Vaciar si startIndex es igual a la longitud de esta instancia y la longitud es cero.


La documentation es bastante explícita acerca de este comportamiento correcto:

Valor de retorno: una cadena que es equivalente a la subcadena que comienza en startIndex en esta instancia, o Empty si startIndex es igual a la longitud de esta instancia.

Emite ArgumentOutOfRangeException si startIndex es menor que cero o * mayor que la longitud de esta instancia. *

En otras palabras, tomar una subcadena que comienza más allá del carácter final le dará una cadena vacía.

Su comentario de que esperaba que le diera una parte de la cadena no es incompatible con esto. Una "parte de la cadena" incluye también el conjunto de todas las subcadenas de longitud cero, como lo demuestra el hecho de que s.substring(n, 0) también proporcionará una cadena vacía.


Lo que hace Subcadena es que comprueba si startIndex es mayor que la longitud de la cadena y solo entonces lanza la excepción. En tu caso es igual (la longitud de la cadena es 3). Después de eso, comprueba si la longitud de la subcadena es cero y si se devuelve String.Empty. En su caso, la longitud de la subcadena es la longitud de la cadena (3) menos el índice de inicio (3). Por esta razón, la longitud de la subcadena es 0 y se devuelve una cadena vacía.


Para complementar otras respuestas, Mono también implementa correctamente este comportamiento.

public String Substring (int startIndex) { if (startIndex == 0) return this; if (startIndex < 0 || startIndex > this.length) throw new ArgumentOutOfRangeException ("startIndex"); return SubstringUnchecked (startIndex, this.length - startIndex); } // This method is used by StringBuilder.ToString() and is expected to // always create a new string object (or return String.Empty). internal unsafe String SubstringUnchecked (int startIndex, int length) { if (length == 0) return String.Empty; string tmp = InternalAllocateStr (length); fixed (char* dest = tmp, src = this) { CharCopy (dest, src + startIndex, length); } return tmp; }

Como puede ver, devuelve String.Empty si la longitud es igual a cero.


Todas las cadenas en C # al final tienen String.Empty .

Aquí hay una buena respuesta a esta pregunta.

De MSDN - String Class (Sistema):

En .NET Framework, un objeto String puede incluir caracteres nulos incrustados, que cuentan como parte de la longitud de la cadena. Sin embargo, en algunos idiomas, como C y C ++, un carácter nulo indica el final de una cadena; no se considera parte de la cadena y no se cuenta como parte de la longitud de la cadena.


A veces mirar el código puede ser útil :

Primero esto se llama:

public string Substring(int startIndex) { return this.Substring(startIndex, this.Length - startIndex); }

La longitud es 0 debido a la resta del valor:

public string Substring(int startIndex, int length) { if (startIndex < 0) { throw new ... } if (startIndex > this.Length) { throw new ... } if (length < 0) { throw new ... } if (startIndex > (this.Length - length)) { throw new ... } if (length == 0) // <-- NOTICE HERE { return Empty; } if ((startIndex == 0) && (length == this.Length)) { return this; } return this.InternalSubString(startIndex, length); }