2011-04-15 4 views
2

Imaginez que mon objectif dans un programme est d'analyser autant d'occurrences de "ab" que possible sur une chaîne. J'aborde ce problème avec le code suivant:Analyse syntaxique Java

public static void main(String[] args) 
{ 
    final String expression = "^(\\s*ab)"; 

    Scanner scanner = new Scanner("ab abab ab"); 

    while (scanner.hasNext()) 
    { 
     String next = scanner.findWithinHorizon(expression, 0); 

     if (next == null) 
     { 
      System.out.println("FAIL"); 
      break; 
     } 
     else 
     { 
      System.out.println(next); 
     } 
    } 
} 

Le caret au début de l'expression est de désavouer quoi que ce soit, mais des espaces au début de chaque lecture comme mentionné here. Il est là pour empêcher quelque chose comme "cab" ou "c ab" d'être autorisé. En fait, je m'attendrais à ce que null soit retourné et que FAIL soit imprimé sur la console si l'un de ces deux cas se produit. Si je supprime le caret de l'expression, il fonctionne parfaitement sur les entrées telles que "ab abab ab", mais ne renvoie pas la valeur null pour "c ab". D'un autre côté, si je laisse le curseur, "c ab" renvoie null comme prévu mais "ab abab ab" échoue. Comment puis-je faire ce travail?

Modifier

Mon message original a peut-être été un peu vague. L'exemple que j'ai donné ci-dessus est une version plus simple de mon vrai problème. le motif ab est un motif de remplissage que je remplacerais par quelque chose de plus intéressant, par exemple une adresse e-mail regex ou une valeur hexadécimale.

Dans mon application, l'entrée du scanner n'est pas une chaîne, mais un flux d'entrée dont je n'ai aucune connaissance. Mon but dans la boucle est de lire les valeurs une à la fois à partir de l'entrée et de vérifier que leur contenu correspond à un modèle. Si c'est le cas, je pourrais faire quelque chose de plus intéressant avec eux. Sinon, le programme se termine.

Dans l'exemple ci-dessus, je me attends à une entrée ab ABAB ab à la sortie:

ab 
ab 
ab 
    ab 

je me attends c ab à la sortie:

FAIL 

et je me attends ab cab à la sortie:

ab 
FAIL 
+0

Votre but est un peu déroutant. Si vous voulez analyser les occurrences de "ab", alors pourquoi "c ab" n'est pas correct? C'est un événement. Voulez-vous dire que vous voulez une chaîne qui n'a que ces 2 caractères dedans? –

+1

pourriez-vous préciser les critères d'appariement et fournir des exemples de chaînes avec les résultats attendus? Vous mentionnez que vous voulez analyser autant d'occurrences de 'ab' d'une chaîne, mais vous dites ensuite que 'cab' et 'c ab' ne devraient pas correspondre. La chaîne doit-elle contenir uniquement la combinaison de lettres «ab»? –

+0

Mise à jour de mon message maintenant. – LandonSchropp

Répondre

4

Dans l'autre thread que vous vouliez correspondre à la première occurence de ab de sorte que le caret était très bien. Si vous voulez faire correspondre toutes les occurrences de ab jusqu'à ce qu'un autre caractère se produit, essayez cette expression: String expression = "\\G(\\s*ab)";

Le \G signifie que le prochain match devrait commencer à la position du précédent arrêté à.

Si je que votre code j'obtenir les résultats suivants:

  1. entrée = "ab ABAB ab", sortie = "ab", "ab", "ab", "ab"

  2. Input = "c ab ab ABAB", sortie = "FAIL"

  3. Input = "ab c ABAB ab", sortie = "ab", "FAIL"

  4. entrée = "ab ABAB ab c ", sortie = "ab", "ab", "ab", "ab", "fail"

+0

C'est cool, Thomas. Exactement ce dont j'avais besoin. Merci encore. – LandonSchropp

+0

Plus d'infos dans la Javadoc de la classe [Pattern] (http://docs.oracle.com/javase/8/docs/api/java/util/regex/Pattern.html) – JavaJigs

0

Bien ... Je pense vous pouvez le faire avec un appel de regex

Essayez le schéma suivant:

expression = "^(\\s*ab*)*$"; 
+0

btw Je pense que vous comprenez que regex est beaucoup plus lent que la simple analyse de corde dans la boucle – VMykyt

+1

... et un autobus scolaire est beaucoup plus lent qu'une Ferrari, mais il traverse le Bay Bridge tout aussi rapidement aux heures de pointe. S'il vous plaît arrêtez de répéter ces avertissements hystériques sur la lenteur des regex. –

0

Si j'ai obtenu votre bonne question, la faute est dans l'expression. Si vous voulez toujours un espace blanc au début, vous devez utiliser^(\ s +) et non^(\ s *) car * peut être 0 occurrences alors que + signifie au moins un.

0

Veuillez comprendre que la méthode findWithinHorizon dans Scanner est pour trouver l'occurrence suivante d'un modèle construit à partir de la chaîne spécifiée et NON pour correspondre à l'entrée entière. Si vous écrivez une expression rationnelle qui correspond à une entrée entière, il retournera simplement le texte d'entrée tel que (selon la réponse de VMykyt ici). Mais ce n'est pas ce que vous voulez, si je comprends bien.

Vous devez donc faire un appel séparé à la méthode String#matches pour vous assurer qu'il n'y a rien d'autre que des espaces devant votre texte et s'il correspond, trouvez simplement toutes les occurrences ab.

Tenir compte de ce changement mineur dans votre code:

public static void main(String[] args) { 
    matchIt("ab abab ab"); 
    matchIt("c ab"); 
    matchIt("cab"); 
} 

private static void matchIt(String str) { 
    final String expression = "ab"; 
    System.out.println("Input: [" + str + ']'); 
    Scanner scanner = new Scanner(str); 

    if(str.matches("^\\s*ab.*$")) { 
     while (scanner.hasNext()) { 
     String next = scanner.findWithinHorizon(expression, 0); 
     if (next == null) { 
      System.out.println("FAIL"); 
      break; 
     } 
     else { 
      System.out.println(next); 
     } 
     } 
    } 
    else 
     System.out.println("FAIL"); 
} 

SORTIE:

Input: [ab abab ab] 
ab 
ab 
ab 
ab 
=========================== 
Input: [c ab] 
FAIL 
=========================== 
Input: [cab] 
FAIL 
===========================