Sortie déroutante de Ssortingng.split

Je ne comprends pas la sortie de ce code:

public class SsortingngDemo{ public static void main(Ssortingng args[]) { Ssortingng blank = ""; Ssortingng comma = ","; System.out.println("Output1: "+blank.split(",").length); System.out.println("Output2: "+comma.split(",").length); } } 

Et a obtenu la sortie suivante:

 Output1: 1 Output2: 0 

Documentation:

Pour: System.out.println("Output1: "+blank.split(",").length);

Le tableau renvoyé par cette méthode contient chaque sous-chaîne de cette chaîne qui est terminée par une autre sous-chaîne qui correspond à l’expression donnée ou qui se termine par la fin de la chaîne. Les sous-chaînes du tableau sont dans l’ordre dans lequel elles apparaissent dans cette chaîne. Si l’expression ne correspond à aucune partie de l’entrée, le tableau résultant n’a qu’un seul élément, à savoir cette chaîne .

Il retournera simplement la chaîne entière, c’est pourquoi elle retourne 1.


Dans le second cas, Ssortingng.split le , le résultat sera donc vide.

 Ssortingng.split silently discards trailing separators 

voir les cordes de goyaveExpliquées aussi

Tout se passe comme prévu, mais faisons-le pas à pas (j’espère que vous avez du temps).

Selon la documentation (et le code source ) de la méthode split(Ssortingng regex) :

Cette méthode fonctionne comme si en invoquant la méthode split à deux arguments avec l’expression donnée et un argument limite de zéro.

Donc, quand vous invoquez

 split(Ssortingng regex) 

vous obtenez réellement le résultat de la méthode split(Ssortingng regex, int limit) qui est invoquée d’une manière:

 split(regex, 0) 

Donc, ici, la limit est fixée à 0 .

Vous devez connaître quelques éléments sur ce paramètre:

  • Si limit est positif, vous limit longueur du tableau de résultats à un nombre positif que vous avez spécifié, donc "axaxaxaxa".split("x",2) renverra un tableau, ["a", "axaxaxa"] , pas ["a","a","a","a","a"] .
  • Si limit est 0 vous ne limit pas la longueur du tableau de résultats. Mais cela signifie également que toutes les chaînes vides seront supprimées. Par exemple:

     "fooXbarX".split("X") 

    va au début générer un tableau qui ressemblera à:

     ["foo", "bar", ""] 

    ( "barX" fractionné sur "X" génère "bar" et "" ), mais puisque split supprime toutes les chaînes vides à la fin, il retournera

     ["foo", "bar"] 
  • Le comportement de la valeur négative de la limit est similaire au comportement où la limite est définie sur 0 (la longueur du tableau de résultats ne sera pas limitée). La seule différence est qu’il ne supprimera pas les chaînes vides de la fin du tableau de résultats. En d’autres termes

     "fooXbarX".split("X",-1) 

reviendra ["foo", "bar", ""]


Regardons le cas,

 ",".split(",").length 

qui (comme expliqué précédemment) est la même que

 ",".split(",", 0).length 

Cela signifie que nous utilisons une version de split qui ne limite pas la longueur du tableau de résultats, mais supprime toutes les chaînes vides à la fin , "" . Vous devez comprendre que lorsque nous divisons une chose, nous obtenons toujours deux choses.

En d’autres termes, si nous séparons "abc" à la place de b , nous obtiendrons "a" et "c" .
La partie délicate est de comprendre que si nous séparons "abc" dans c nous obtiendrons "ab" et "" (chaîne vide).

En utilisant cette logique, si nous nous séparons "," on obtiendra "" et "" (deux chaînes vides).

Vous pouvez le vérifier en utilisant split avec une limite négative:

 for (Ssortingng s: ",".split(",", -1)){ System.out.println("\""+s+"\""); } 

qui imprimera

 "" "" 

Donc, comme nous le voyons, le tableau est d’abord ["", ""] .

Mais comme nous utilisons par défaut la limit définie sur 0 , toutes les chaînes vides à la fin seront supprimées. Dans ce cas, le tableau de résultats ne contient que des chaînes vides finales , elles seront toutes supprimées , vous laissant un tableau vide [] longueur 0 .


Pour répondre au cas avec

 "".split(",").length 

vous devez comprendre que la suppression des chaînes vides finales n’a de sens que si de telles chaînes vides résultent du fractionnement (et ne sont probablement pas nécessaires) .
Donc, s’il n’y avait pas d’endroits sur lesquels nous pouvions nous séparer, il n’y a aucune chance que des chaînes vides soient créées, il est donc inutile de lancer ce processus de “nettoyage”.

Cette information est mentionnée dans la documentation de la méthode split(Ssortingng regex, int limit) où vous pouvez lire:

Si l’expression ne correspond à aucune partie de l’entrée, le tableau résultant n’a qu’un seul élément, à savoir cette chaîne .

Vous pouvez également voir ce comportement dans le code source de cette méthode (à partir de Java 8):

  2316 public Ssortingng [] split (regex, int limit) { 
2317 / * fastpath si le regex est un
2318 (1) une chaîne de caractères et ce caractère ne fait pas partie des
2319 Les méta-caractères de RegEx ". $ | () [{^? * + \\", ou
2320 (2) Chaîne à deux caractères et le premier caractère est la barre oblique inverse et
2321 le second n'est pas le chiffre ascii ou la lettre ascii.
2322 * /
2323 char ch = 0;
2324 si (((regex.value.length == 1 &&
2325 ". $ | () [{^? * + \\". indexOf (ch = regex. charAt (0)) == -1) ||
2326 (regex. Length () == 2 &&
2327 regex. charAt (0) == '\\' &&
2328 (((ch = regex. CharAt (1)) - '0') | ('9'-ch)) <0 &&
2329 ((ch-'a') | ('z'-ch)) <0 &&
2330 ((ch-'A') | ('Z'-ch)) <0)) &&
2331 (ch 2332 ch> Character.MAX_LOW_SURROGATE))
2333 {
2334 int off = 0;
2335 int next = 0;
2336 booléen limité = limite> 0;
2337 ArrayList < String > list = new ArrayList <> ();
2338 while ((next = indexOf (ch, off))! = -1) {
2339 if (! Limited || list. Size () 2340 liste. append ( sous-chaîne (off, next));
2341 éteint = suivant + 1;
2342 } else {// dernier
2343 // assert (list.size () == limit - 1);
2344 liste. append ( sous-chaîne (off, value.length));
2345 off = value.length;
2346 pause ;
2347 }
2348 }
2349 // Si aucune correspondance n'a été trouvée, retournez cette
2350 si (off == 0)
2351 return new Ssortingng [] { this };
2353 // Ajouter le segment restant
2354 if (! Limited || list. Size ()
2355 liste. append ( sous-chaîne (off, value.length));
2357 // Résultat de construction
2358 int resultSize = liste. taille ();
2359 si (limite == 0) {
2360 while (resultSize> 0 && list. Get (resultSize - 1). Length () == 0) {
2361 resultSize--;
2362 }
2363 }
2364 Ssortingng [] resultat = new Chaîne [resultSize];
2365 liste de retour . sous-liste (0, resultSize). toArray (résultat);
2366 }
2367 Modèle de retour . comstackr (regex). split ( this , limit);
2368 }

où vous pouvez trouver

 if (off == 0) return new Ssortingng[]{this}; 

fragment qui signifie

  • if (off == 0) – si off (la position à partir de laquelle la méthode doit commencer à chercher la prochaine correspondance possible pour regex passée en argument split ) est toujours 0 après itération sur la chaîne entière, nous n’avons trouvé aucune correspondance. pas diviser
  • return new Ssortingng[]{this}; – dans ce cas, retournons simplement un tableau avec la chaîne d’origine (représentée par this ).

Puisque "," ne pouvait pas être trouvé dans "" même une fois, "".split(",") doit retourner un tableau avec un élément (chaîne vide sur laquelle vous avez invoqué la split ). Cela signifie que la longueur de ce tableau est 1 .

BTW Java 8 a introduit un autre mécanisme. Il supprime les principales chaînes vides (si elles ont été créées lors du fractionnement du processus) si nous les scindons en utilisant une expression régulière de longueur nulle (comme "" ou avec une référence (?< !x) ). Plus d'infos sur: Pourquoi, en Java 8, le split supprime parfois des chaînes vides au début du tableau de résultats?

À partir de la documentation Java 1.7

Divise la chaîne autour des correspondances de l’expression régulière donnée.

La méthode split () fonctionne comme si on appelait la méthode split à deux arguments avec l’expression donnée et un argument limite de zéro. Les chaînes vides à la fin ne sont donc pas incluses dans le tableau résultant.

Dans le cas 1, blank.split(",") does not match any part of the input then the resulting array has just one element, namely this Ssortingng.

It will return entire Ssortingng. Donc, la longueur sera 1 .

Dans le cas 2, comma.split(",") will return empty.

split() attend un regex comme argument, retourne le tableau de résultats à la correspondance avec ce regex.

Donc, la longueur est 0

Par exemple ( documentation )

La chaîne “boo: and: foo” donne les résultats suivants avec ces expressions:

 Regex Result : { "boo", "and", "foo" } o { "b", "", ":and:f" } 

Paramètres: regex – l’expression régulière délimitant

Retourne: le tableau de chaînes calculé en divisant cette chaîne autour des correspondances de l’expression régulière donnée

Lève: PatternSyntaxException – si la syntaxe de l’expression régulière n’est pas valide

De la classe Ssortingng javadoc pour la méthode public Ssortingng[] split (Ssortingng regex) :

Divise cette chaîne autour des correspondances de l’expression régulière donnée.

Cette méthode fonctionne comme si en invoquant la méthode split à deux arguments avec l’expression donnée et un argument limite de zéro. Les chaînes vides à la fin ne sont donc pas incluses dans le tableau résultant.

Dans le premier cas, l’expression ne correspond à aucune partie de l’entrée, nous avons donc un tableau avec un seul élément: l’entrée.

Dans le second cas, l’expression correspond à input et split devrait renvoyer deux chaînes vides; mais, selon javadoc, ils sont rejetés (parce qu’ils sont à la traîne et vides).

Nous pouvons examiner le code source de java.util.regex.Pattern qui se trouve derrière Ssortingng.split . Descendre le terrier du lapin

 public Ssortingng[] split(CharSequence input, int limit) 

est invoqué.

Entrée ""

Pour l’entrée "" cette méthode est appelée

 Ssortingng[] parts = split("", 0); 

La partie intéressante de cette méthode est la suivante :

  int index = 0; boolean matchLimited = limit > 0; ArrayList matchList = new ArrayList<>(); Matcher m = matcher(input); while(m.find()) { // Tichodroma: this will not happen for our input } // If no match was found, return this if (index == 0) return new String[] {input.toString()}; 

Et c’est ce qui se passe: new Ssortingng[] {input.toSsortingng()} est renvoyé .

Entrée ","

Pour l’entrée "," la partie interessante est

  // Construct result int resultSize = matchList.size(); if (limit == 0) while (resultSize > 0 && matchList.get(resultSize-1).equals("")) resultSize--; Ssortingng[] result = new Ssortingng[resultSize]; return matchList.subList(0, resultSize).toArray(result); 

Ici resultSize == 0 et limit == 0 donc la new Ssortingng[0] est retournée .

A partir de JDK 1.7

  public Ssortingng[] split(Ssortingng regex, int limit) { /* fastpath if the regex is a (1)one-char Ssortingng and this character is not one of the RegEx's meta characters ".$|()[{^?*+\\", or (2)two-char Ssortingng and the first char is the backslash and the second is not the ascii digit or ascii letter. */ char ch = 0; if (((regex.count == 1 && ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) || (regex.length() == 2 && regex.charAt(0) == '\\' && (((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 && ((ch-'a')|('z'-ch)) < 0 && ((ch-'A')|('Z'-ch)) < 0)) && (ch < Character.MIN_HIGH_SURROGATE || ch > Character.MAX_LOW_SURROGATE)) { int off = 0; int next = 0; boolean limited = limit > 0; ArrayList list = new ArrayList<>(); while ((next = indexOf(ch, off)) != -1) { if (!limited || list.size() < limit - 1) { list.add(substring(off, next)); off = next + 1; } else { // last one //assert (list.size() == limit - 1); list.add(substring(off, count)); off = count; break; } } // If no match was found, return this if (off == 0) return new String[] { this }; // Add remaining segment if (!limited || list.size() < limit) list.add(substring(off, count)); // Construct result int resultSize = list.size(); if (limit == 0) while (resultSize > 0 && list.get(resultSize-1).length() == 0) resultSize--; Ssortingng[] result = new Ssortingng[resultSize]; return list.subList(0, resultSize).toArray(result); } return Pattern.comstack(regex).split(this, limit); } 

Donc, dans ce cas, le regex sera traité par le premier if .

Pour le premier cas blank.split(",")

 // If no match was found, return this if (off == 0) return new Ssortingng[] { this }; 

Donc, cette fonction retournera un tableau qui contient un élément s’il n’y a pas de correspondance.

Pour le deuxième cas, comma.split(",")

 List list = new ArrayList<>(); //... int resultSize = list.size(); if (limit == 0) while (resultSize > 0 && list.get(resultSize-1).length() == 0) resultSize--; Ssortingng[] result = new Ssortingng[resultSize]; return list.subList(0, resultSize).toArray(result); 

Comme vous le constatez, la dernière boucle while a supprimé tous les éléments vides à la fin de la liste. La valeur resultSize est donc 0 .

 Ssortingng blank = ""; Ssortingng comma = ","; System.out.println("Output1: "+blank.split(",").length); // case 1 System.out.println("Output2: "+comma.split(",").length); // case 2 

case 1 – Ici, blank.split(",") renverra "" car il n’y a pas , en blank vous obtenez la même chose, donc la longueur sera 1

case 2- Ici, comma.split(",") renverra un tableau vide, vous devez modifier , si vous voulez compter les comma de longueur 1 sinon la longueur sera 0

Là encore, comma.split(",") split () attend un regex comme argument, il renverra le tableau de résultats à cette regex .

Le tableau renvoyé par cette méthode contient chaque sous-chaîne de cette chaîne qui est terminée par une autre sous-chaîne qui correspond à l’expression donnée ou qui se termine par la fin de la chaîne.

Autre

Si l’expression ne correspond à aucune partie de l’entrée, le tableau résultant n’a qu’un seul élément, à savoir cette chaîne.

L’API de la méthode split indique que “Si l’expression ne correspond à aucune partie de l’entrée, le tableau résultant n’a qu’un seul élément, à savoir cette chaîne.”

Ainsi, comme le champ Ssortingng ne contient pas de “,”, un Ssortingng [] avec un élément (c.-à-d. Lui-même vide) est renvoyé.

Pour la virgule Ssortingng, il ne rest “rien” de la chaîne d’origine, donc un tableau vide est renvoyé.

Cela semble être la meilleure solution si vous souhaitez traiter le résultat renvoyé, par exemple

 Ssortingng[] splits = aSsortingng.split(","); for(Ssortingng split: splits) { // do something }