web-dev-qa-db-fra.com

Pourquoi "split" sur une chaîne vide renvoie-t-il un tableau non vide?

Fractionner sur une chaîne vide renvoie un tableau de taille 1:

scala> "".split(',')
res1: Array[String] = Array("")

Considérez que cela retourne un tableau vide:

scala> ",,,,".split(',')
res2: Array[String] = Array()

S'il vous plaît, expliquez :)

89
oluies

Pour la même raison que

",test" split ','

et

",test," split ','

retournera un tableau de taille 2. Tout ce qui se trouve avant la première correspondance est retourné en tant que premier élément.

32
Daniel C. Sobral

Si vous divisez une fois le zéro orange, vous avez exactement une pièce - l’orange.

63
Sam Stainsby

Fractionner une chaîne vide renvoie la chaîne vide en tant que premier élément. Si aucun délimiteur n'est trouvé dans la chaîne cible, vous obtiendrez un tableau de taille 1 contenant la chaîne d'origine, même si elle est vide.

40
Nick Rolando

Les méthodes Java et Scala) fonctionnent en deux étapes, comme suit:

  • Commencez par diviser la chaîne par un délimiteur. La conséquence naturelle est que si la chaîne ne contient pas le délimiteur, un tableau singleton contenant uniquement la chaîne d'entrée est renvoyé.
  • Deuxièmement, supprimez toutes les chaînes vides les plus à droite. C'est la raison pour laquelle ",,,".split(",") renvoie un tableau vide.

Selon cela, le résultat de "".split(",") devrait être un tableau vide à cause de la deuxième étape, non?

Cela devrait. Malheureusement, il s’agit d’un cas de corner introduit artificiellement. Et c’est mauvais, mais au moins cela est documenté dans Java.util.regex.Pattern, si vous vous rappelez de consulter la documentation:

Pour n == 0, le résultat est identique à n <0, sauf que les chaînes vides en fin de chaîne ne seront pas renvoyées. (Notez que le cas où l'entrée est en soi une chaîne vide est spécial, comme décrit ci-dessus, et le paramètre limit ne s'y applique pas.)

Solution 1: passez toujours -1 comme second paramètre

Donc, je vous conseille de toujours passer n == -1 en tant que deuxième paramètre (cette étape passera à l'étape 2 ci-dessus), à moins que vous ne sachiez exactement ce que vous voulez atteindre/vous êtes certain que la chaîne vide ne sera pas quelque chose que votre programme obtiendrait en entrée.

Solution 2: utilisez la classe Guava Splitter

Si vous utilisez déjà Guava dans votre projet, vous pouvez essayer la classe Splitter (documentation) . Il possède une API très riche et rend votre code très facile à comprendre.

Splitter.on(".").split(".a.b.c.") // "", "a", "b", "c", ""
Splitter.on(",").omitEmptyStrings().split("a,,b,,c") // "a", "b", "c"
Splitter.on(CharMatcher.anyOf(",.")).split("a,b.c") // "a", "b", "c"
Splitter.onPattern("=>?").split("a=b=>c") // "a", "b", "c"
Splitter.on(",").limit(2).split("a,b,c") // "a", "b,c"
36
Rok Kralj

"a".split(",") -> "a" donc "".split(",") -> ""

22
weberjn

Dans tous les langages de programmation, je sais qu'une chaîne vide est toujours une chaîne valide. Donc, faire une scission en utilisant n'importe quel délimiteur renverra toujours un seul tableau d'éléments où cet élément est la chaîne vide. S'il s'agissait d'une chaîne nulle (non vide), le problème serait différent.

4
brent777

Ce comportement split est hérité de Java, pour le meilleur ou pour le pire ...
Scala ne remplace pas la définition de la primitive String.

Notez que vous pouvez utiliser l'argument limit pour modifier le comportement :

Le paramètre limit contrôle le nombre d'applications du modèle et affecte donc la longueur du tableau résultant. Si la limite n est supérieure à zéro, le motif sera appliqué au plus n fois - 1 fois, la longueur du tableau ne sera pas supérieure à n et la dernière entrée du tableau contiendra toutes les entrées au-delà du dernier délimiteur mis en correspondance. Si n est non positif, le motif sera appliqué autant de fois que possible et le tableau peut avoir n'importe quelle longueur. Si n est égal à zéro, le modèle sera appliqué autant de fois que possible, le tableau peut avoir n'importe quelle longueur et les chaînes vides suivantes seront ignorées.

c'est-à-dire que vous pouvez régler le limit=-1 pour obtenir le comportement de toutes les autres langues:

@ ",a,,b,,".split(",")
res1: Array[String] = Array("", "a", "", "b")

@ ",a,,b,,".split(",", -1)  // limit=-1
res2: Array[String] = Array("", "a", "", "b", "", "")

Il semble bien connu que le comportement de Java) est assez déroutant mais:

Le comportement ci-dessus peut être observé depuis au moins Java 5 à Java 8.

Une tentative de modification du comportement afin de renvoyer un tableau vide lors du fractionnement d'une chaîne vide dans JDK-6559590 . Cependant, il a été rapidement annulé dans JDK-8028321 lorsqu'il a provoqué une régression à divers endroits. La modification ne le fait jamais dans la version initiale Java 8).

Remarque: La méthode de scission n'était pas dans Java depuis le début (c'est ) et non dans 1.0.2 ) mais existe en réalité d’au moins 1,4 (voir par exemple JSR51 vers 2002). Je suis toujours en train d’enquêter sur ...

Ce qui est incertain, c’est pourquoi Java a choisi ceci en premier lieu (je soupçonne qu’il s’agissait à l’origine d’un oubli/bogue dans un "cas Edge")), mais qu’il était désormais irrévocablement intégré au langage et ainsi il reste .

2
Andy Hayden

Les chaînes vides n'ont aucun statut particulier lors du fractionnement d'une chaîne. Vous pouvez utiliser:

Some(str)
  .filter(_ != "")
  .map(_.split(","))
  .getOrElse(Array())
0
Hanan Oanunu