web-dev-qa-db-fra.com

Comment fonctionne string.split ("\\ S")

Je faisais une question sur le livre Oracle_certified_professional_Java_se_7_programmer_exams_1z0-804_and_1z0-805 de Ganesh et Sharma.

Une question est:

  1. Considérez le programme suivant et prédisez la sortie:

      class Test {
    
        public static void main(String args[]) {
          String test = "I am preparing for OCPJP";
          String[] tokens = test.split("\\S");
          System.out.println(tokens.length);
        }
      }
    

    a) 0

    b) 5

    c) 12

    d) 16

Maintenant, je comprends que\S est un regex signifie que les caractères non spatiaux sont traités comme des délimiteurs. Mais j'étais perplexe quant à la façon dont l'expression d'expression régulière fait son appariement et quels sont les jetons réels produits par split.

J'ai ajouté du code pour imprimer les jetons comme suit

for (String str: tokens){
  System.out.println("<" + str + ">");
}

et j'ai obtenu la sortie suivante

16

<>

< >

<>

< >

<>

<>

<>

<>

<>

<>

<>

<>

< >

<>

<>

< >

Donc, beaucoup de jetons de chaîne vides. Je ne comprends tout simplement pas cela.

J'aurais pensé dans le sens que si les délimiteurs ne sont pas des caractères spatiaux, dans le texte ci-dessus, tous les caractères alphabétiques servent de délimiteurs, alors il devrait peut-être y avoir 21 jetons si nous faisons correspondre des jetons qui entraînent également des chaînes vides. Je ne comprends tout simplement pas comment le moteur regex de Java fonctionne. Y a-t-il des gourous des regex qui peuvent faire la lumière sur ce code pour moi?

13
Frank Brosnan

Les premières choses commencent par \s (en minuscules), qui est une classe de caractères d'expression régulière pour les espaces blancs, c'est-à-dire l'espace '' tabs '\ t', les nouveaux caractères de ligne '\ n' et '\ r', l'onglet vertical '\ v' et un tas d'autres personnages.

\S (majuscule) est l'opposé de cela, ce qui signifierait tout caractère non blanc.

Ainsi, lorsque vous divisez cette chaîne "I am preparing for OCPJP" en utilisant \S vous fractionnez efficacement la chaîne à chaque lettre. La raison pour laquelle votre tableau de jetons a une longueur de 16.

Maintenant pour savoir pourquoi ceux-ci sont vides.

Considérez la chaîne suivante: Hello,World, si nous devions diviser cela en utilisant ,, nous nous retrouverions avec un tableau String de longueur 2, avec le contenu suivant: Hello et World. Notez que le , n'est dans aucune des chaînes, il a été effacé.

La même chose s'est produite avec le I am preparing for OCPJP Chaîne, elle a été divisée et les points correspondant à votre expression régulière ne figurent dans aucune des valeurs renvoyées. Et comme la plupart des lettres de cette chaîne sont suivies d'une autre lettre, vous vous retrouvez avec une charge de chaînes de longueur zéro, seuls les caractères d'espace blanc sont conservés.

5
PeterK

Copié de l'API documentation : (les gras sont les miens)

public String[] split(String regex)

Fractionne cette chaîne autour des correspondances de l'expression régulière donnée. Cette méthode fonctionne comme si en appelant la méthode de fractionnement à deux arguments avec l'expression donnée et un argument limite de zéro. Les chaînes vides de fin ne sont donc pas incluses dans le tableau résultant.

La chaîne "boo: and: foo", par exemple, donne les résultats suivants avec ces expressions:

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

Vérifiez le deuxième exemple, où les 2 derniers "o" sont supprimés: la réponse à votre question est "OCPJP" la sous-chaîne est traitée comme une collection de séparateurs qui n'est pas suivie pour les chaînes non vides, de sorte que la partie est tronquée.

12
Pablo Lozano

La raison pour laquelle le résultat est 16 et non 21 est la suivante, à partir du javadoc pour Split :

Les chaînes vides de fin ne sont donc pas incluses dans le tableau résultant.

Cela signifie, par exemple, que si vous dites

"/abc//def/ghi///".split("/")

le résultat comportera cinq éléments. Le premier sera "", car ce n'est pas une chaîne vide de fin; les autres seront "abc", "", "def", et "ghi". Mais les chaînes vides restantes sont supprimées du tableau.

Dans le cas affiché:

"I am preparing for OCPJP".split("\\S")

c'est la même chose. Étant donné que les caractères non espace sont des délimiteurs, chaque lettre est un délimiteur, mais les lettres OCPJP ne comptent essentiellement pas, car ces délimiteurs entraînent des chaînes vides à la fin qui sont ensuite jetés. Donc, puisqu'il y a 15 lettres dans "I am preparing for", elles sont traitées comme délimitant 16 sous-chaînes (la première est "" et le dernier est " ").

6
ajb