Avant Java 8 lorsque nous nous sommes séparés sur une chaîne vide comme
String[] tokens = "abc".split("");
le mécanisme de division se diviserait aux endroits marqués |
|a|b|c|
car un espace vide ""
existe avant et après chaque caractère. Donc, en conséquence, il générerait d'abord ce tableau
["", "a", "b", "c", ""]
et plus tard, supprimera les chaînes vides de fin (car nous n'avons pas explicitement fourni de valeur négative à l' limit
argument) afin qu'il retourne finalement
["", "a", "b", "c"]
Dans Java 8, le mécanisme de partage semble avoir changé. Maintenant quand nous utilisons
"abc".split("")
nous obtiendrons un ["a", "b", "c"]
tableau au lieu de ["", "a", "b", "c"]
cela, il semblerait que les chaînes vides au début soient également supprimées. Mais cette théorie échoue parce que par exemple
"abc".split("a")
renvoie un tableau avec une chaîne vide au début ["", "bc"]
.
Quelqu'un peut-il expliquer ce qui se passe ici et comment les règles de partage ont changé dans Java 8?
s.split("(?!^)")
semble fonctionner.split("")
lieu de cryptique (pour les personnes qui n'utilisent pas regex)split("(?!^)")
ousplit("(?<!^)")
ou quelques regexes d'autres.Réponses:
Le comportement de
String.split
(qui appellePattern.split
) change entre Java 7 et Java 8.Documentation
En comparant la documentation de
Pattern.split
dans Java 7 et Java 8 , nous observons l'ajout de la clause suivante:La même clause est également ajoutée
String.split
dans Java 8 , par rapport à Java 7 .Implémentation de référence
Comparons le code de
Pattern.split
l'implémentation de référence en Java 7 et Java 8. Le code est récupéré depuis grepcode, pour les versions 7u40-b43 et 8-b132.Java 7
Java 8
L'ajout du code suivant dans Java 8 exclut la correspondance de longueur nulle au début de la chaîne d'entrée, ce qui explique le comportement ci-dessus.
Maintenir la compatibilité
Comportement suivant dans Java 8 et supérieur
Pour rendre le
split
comportement cohérent entre les versions et compatible avec le comportement de Java 8:(?!\A)
à la fin de l'expression régulière et enveloppez l'expression régulière d'origine dans un groupe non capturant(?:...)
(si nécessaire).(?!\A)
vérifie que la chaîne ne se termine pas au début de la chaîne, ce qui implique que la correspondance est une correspondance vide au début de la chaîne.Comportement suivant dans Java 7 et antérieurs
Il n'y a pas de solution générale pour rendre la
split
compatibilité descendante avec Java 7 et les versions antérieures, à moins de remplacer toutes les instances desplit
pour pointer vers votre propre implémentation personnalisée.la source
split("")
code pour qu'il soit cohérent entre les différentes versions de Java?(?!^)
à la fin de l'expression régulière et en enveloppant l'expression régulière d'origine dans un groupe non capturant(?:...)
(si nécessaire), mais je ne peux penser à aucun moyen de le rendre rétrocompatible (suivez l'ancien comportement de Java 7 et antérieurs)."(?!^)"
? Dans quels scénarios sera-t-il différent""
? (Je suis terrible en regex!: - /).Pattern.MULTILINE
indicateur, alors qu'il\A
correspond toujours au début de la chaîne indépendamment des indicateurs.Cela a été spécifié dans la documentation de
split(String regex, limit)
.Dans
"abc".split("")
vous avez une correspondance de largeur nulle au début, de sorte que la sous-chaîne vide de début n'est pas incluse dans le tableau résultant.Cependant, dans votre deuxième extrait de code lorsque vous vous divisez,
"a"
vous avez une correspondance de largeur positive (1 dans ce cas), de sorte que la sous-chaîne de début vide est incluse comme prévu.(Suppression du code source non pertinent)
la source
Il y a eu un léger changement dans la documentation pour passer
split()
de Java 7 à Java 8. Plus précisément, la déclaration suivante a été ajoutée:(c'est moi qui souligne)
Le fractionnement de chaîne vide génère une correspondance de largeur nulle au début, donc une chaîne vide n'est pas incluse au début du tableau résultant conformément à ce qui est spécifié ci-dessus. En revanche, votre deuxième exemple qui se divise sur
"a"
génère une correspondance de largeur positive au début de la chaîne, donc une chaîne vide est en fait incluse au début du tableau résultant.la source
"some-string".split("")
s'agit d'un cas assez rare..split("")
n'est pas le seul moyen de se séparer sans rien égaler. Nous avons utilisé une expression régulière lookahead positive qui, dans jdk7, correspondait également au début et produisait un élément head vide qui a maintenant disparu. github.com/spray/spray/commit/…