web-dev-qa-db-fra.com

Pourquoi «hors de portée» n'est-il pas renvoyé pour «sous-chaîne (startIndex, endIndex)»

Dans Java j'utilise la méthode substring() et je ne sais pas pourquoi elle ne renvoie pas une erreur "out of index".

La chaîne abcde a un début d'index de 0 à 4, mais la méthode substring() prend startIndex et endIndex comme arguments basés sur le fait que je peux appeler foo.substring (0) et obtenir "abcde ".

Alors pourquoi la sous-chaîne (5) fonctionne-t-elle? Cet indice devrait être hors de portée. Quelle est l'explication?

/*
1234
abcde
*/
String foo = "abcde";
System.out.println(foo.substring(0));
System.out.println(foo.substring(1));
System.out.println(foo.substring(2));
System.out.println(foo.substring(3));
System.out.println(foo.substring(4));
System.out.println(foo.substring(5));

Ce code génère:

abcde
bcde
cde
de
e
     //foo.substring(5) output nothing here, isn't this out of range?

Quand je remplace 5 par 6:

foo.substring(6)

Ensuite, je reçois une erreur:

Exception in thread "main" Java.lang.StringIndexOutOfBoundsException:
    String index out of range: -1
18
Meow

Selon le Java API doc , la sous-chaîne génère une erreur lorsque l'index de début est supérieur à la longueur de la chaîne.

IndexOutOfBoundsException - si beginIndex est négatif ou supérieur à la longueur de cet objet String.

En fait, ils donnent un exemple un peu comme le vôtre:

"emptiness".substring(9) returns "" (an empty string)

Je suppose que cela signifie qu'il est préférable de penser à une chaîne Java comme suit, où un index est enveloppé dans |:

|0| A |1| B |2| C |3| D |4| E |5|

C'est-à-dire qu'une chaîne a à la fois un index de début et de fin.

21
Matt Mitchell

Lorsque vous effectuez foo.substring(5), la sous-chaîne commence à la position juste après le "e" et se termine à la fin de la chaîne. Soit dit en passant, les positions de début et de fin se trouvent être les mêmes. Ainsi, chaîne vide. Vous pouvez considérer l'index comme n'étant pas un caractère réel dans la chaîne, mais une position entre les caractères.

        ---------------------
String: | a | b | c | d | e |
        ---------------------
Index:  0   1   2   3   4   5
16
Jeff

C'est parce que la fonction de sous-chaîne renvoie une sous-chaîne "inclusive". L'index 5 pointe donc vers un emplacement AVANT la fin de la chaîne, mais APRÈS le dernier caractère d'affichage de la chaîne.

Cela est indiqué dans la documentation: http://download.Oracle.com/docs/cd/E17476_01/javase/1.4.2/docs/api/Java/lang/String.html#substring (int)

3
Josiah

Depuis l'API String javadoc:

public String substring(int beginIndex)
    Returns a new string that is a substring of this 
    string. The substring begins with the "" character 
    at the specified index and extends to the end of this string.

public String substring(int beginIndex, int endIndex)
    Returns a new string that is a substring of this 
    string. The substring begins at the specified beginIndex 
    and extends to the character at index endIndex - 1. Thus 
    the length of the substring is endIndex-beginIndex.

Exemples:

"unhappy".substring(2) returns "happy" 
"Harbison".substring(3) returns "bison"
"emptiness".substring(9) returns "" (an empty string)

"hamburger".substring(4, 8) returns "urge"
"smiles".substring(1, 5) returns "mile"

Paramètres:

beginIndex - the beginning index, inclusive.
Returns:
the specified substring.
Throws:
IndexOutOfBoundsException - if beginIndex is negative or 
larger than the length of this String object.

====

C'est donc par conception. Si vous donnez à l'index la taille de la chaîne, il renvoie une chaîne vide.

3
samitgaur

Je sais que ce fil est assez ancien, mais c'est un problème tellement fondamental que je pense qu'il mérite une clarification.

La question est correctement posée. Je considère cela comme une erreur logicielle dans la méthode Java String.substring (int beginIndex, int endIndex)).

http://docs.Oracle.com/javase/7/docs/api/Java/lang/String.html#substring%28int,%20int%29 .

Depuis les Java Docs https://docs.Oracle.com/javase/tutorial/Java/nutsandbolts/arrays.html

Java Arrays

Java/C/C++ et tous les autres langages que je connais ne voient PAS l'index du tableau comme le "diviseur" entre les éléments du tableau.

Paramètres: beginIndex - l'index de début, inclus. endIndex - l'index de fin, exclusif.

Soit endIndex est mal nommé car le langage ne permet pas l'accès en mémoire à l'adresse à endIndex + 1 qui est nécessaire pour inclure le dernier élément du tableau OR endIndex est mal défini et doit être: endIndex - le indice de fin, inclus.

Le cas le plus probable est que le deuxième paramètre a été mal nommé. Il doit être: longueur - la longueur de la chaîne souhaitée commençant à beginIndex.

Nous savons que Gosling a basé la syntaxe Java sur les langages C/C++ pour la familiarité. De la classe de chaîne C+++ http://www.cplusplus.com/reference/string/string/ substr / nous voyons que la définition de la méthode est:

chaîne substr (size_t pos = 0, size_t len ​​= npos) const;

Notez que le deuxième paramètre de la définition de méthode est "len" pour la longueur.

len Nombre de caractères à inclure dans la sous-chaîne (si la chaîne est plus courte, autant de caractères que possible sont utilisés).

testString a 10 caractères, les positions d'index 0 à 9. La spécification d'un endIndex de 10 devrait toujours lever l'IndexOutOfBoundsException () car testString n'a pas de endIndex de 10.

Si nous testons la méthode dans JUnit avec des valeurs concrètes en regardant la méthode C++, nous nous attendons à:

String testString = "testString"; assertThat (testString.substring (4, 6), equalTo ("String"));

mais bien sûr on obtient Attendu: "String" mais était "St"

La longueur de testString de l'index 0 au caractère "g" dans "String" est de 10 caractères. Si nous utilisons 10 comme paramètre "endIndex",

String testString = "testString"; assertThat (testString.substring (4, 10), equalTo ("String"));

"Pass" de JUnit.

Si nous renommons le paramètre 2 en "lengthOfSubstringFromIndex0", vous n'avez pas à effectuer le décompte endIndex - 1, et il ne lève jamais l'indexOutOfBoundsException () qui est attendu lors de la spécification d'un endIndex, 10, qui est hors de portée du tableau sous-jacent. http://docs.Oracle.com/javase/7/docs/api/Java/lang/IndexOutOfBoundsException.html

C'est juste une de ces fois où vous devez vous rappeler l'idiosyncrasie de cette méthode. Le deuxième paramètre n'est pas nommé correctement. La signature de la méthode Java doit être:

public String substring(int beginIndex,
           int lengthOfSubstringFromIndex0)

Ou la méthode redéfinie pour correspondre à la méthode C++ string :: substr. La redéfinition, bien sûr, signifierait une réécriture de l'ensemble d'Internet, il est donc peu probable.

3
Ted Spradley

substring (5) pointe vers un index existant ... il se trouve juste qu'il pointe vers une chaîne vide. substring (6), d'autre part, est juste un discours fou. :)

2
Faisal