2017-07-05 1 views
3

Entré en conflit avec un comportement étrange de correspondance d'expressions rationnelles en Java. La première commande de sortie imprime true comme prévu, mais lorsque la même chaîne est compressée dans Scanner, la sortie est false. Qu'est-ce que je fais mal?Java: le comportement se comporte différemment dans Scanner

public static void main(String[] args) { 
    Pattern p = Pattern.compile(" *\\["); 
    System.out.println(p.asPredicate().test("[]")); //true 

    Scanner s = new Scanner("[]"); 
    System.out.println(s.hasNext(" *\\[")); //false 
} 
+0

Essayez avec 's.hasNext (p)' – horcrux

+0

@horcrux De javadoc: * Une invocation de cette méthode de la forme hasNext (modèle * se comporte exactement de la même manière que l'invocation * hasNext (Pattern.compile (motif)). * – SpaceTrucker

+1

@SpaceTrucker Vous avez raison. Donc le point est que 'Pattern.compile (myRegex) p.asPredicate(). Test (myString)' recherche une occurrence de 'myRegex' dans' myString', tandis que 'new Scanner (myString) .hasNext (myRegex)' vérifie si tout le contenu de 'myString' correspond à' myRegex'. – horcrux

Répondre

6

De public boolean hasNext(String pattern)documentation:

Renvoie true si le jeton suivant correspond au modèle construit à partir de la chaîne spécifiée.

Ici prochain jeton est [] pas seulement [ (puisque delimiter est un ou plusieurs espaces) mais " *\\[" modèle ne correspond pas à ce jeton entièrement (] ne correspond pas) si vous êtes informé par résultat false .

Si vous voulez vérifier si le jeton commence par [ vous pouvez ajouter .* à la fin de votre modèle pour le laisser correspondre au reste du jeton. Vous pouvez également supprimer * puisque les espaces sont délimiteurs par défaut, donc ils ne peuvent pas faire partie du jeton.


En cas de

Pattern p = Pattern.compile(" *\\["); 
System.out.println(p.asPredicate().test("a[]")); //true 

Si vous jetez un oeil à code de asPredicate vous le verrez est mis en œuvre comme:

public Predicate<String> asPredicate() { 
    return s -> matcher(s).find(); 
} 

méthode find() ne vérifie pas si la chaîne entière correspond au motif, mais essaie de trouver une partie de celui-ci qui correspond au motif. Puisque [] contient zéro ou plusieurs espaces suivis de [, vous voyez true comme résultat.

+0

Je vois. Est-il possible de vérifier le début d'un jeton, ou devrais-je ajouter '. *' À la fin de chaque regex? –

+0

Ici la manière la plus simple serait d'ajouter '. *' À la fin. Mais en fonction de ce que vous voulez vraiment réaliser peut-être qu'il vaut mieux éviter Scanner et utiliser Pattern directement? C'est difficile à dire sans savoir ce que vous voulez vraiment réaliser. – Pshemo

+0

J'analyse la chaîne, contenant un tableau de type JSON, j'ai donc besoin à la fois d'un accès direct aux caractères et d'un moyen facile d'analyser tout int ou float. Y at-il une alternative à Scanner dans cette situation. L'utilisation de l'analyseur JSON n'est pas une option, ce cas ne peut pas être traité de manière générique. –

0

Selon Predicate.test Description de Javadoc:

. vrai si l'argument d'entrée correspond au prédicat, sinon false

Ce qui est pas écrit explicitement dans Javadoc mais implicite est que la méthode test(T t) ne correspond pas comme méthode String.matches(String), où commencent et ancrages d'extrémité sont implicites. D'autre part, la méthode test ne correspond pas à la chaîne complète et vous devrez utiliser des ancres dans votre expression régulière pour qu'elle se comporte comme String.matches ou Scanner.hasNext(Pattern).

code suivant donnera cohérence false résultat à la fois les appels

final String input = "[]"; 
final String re = "^ *\\[$"; // note use of anchors in the regex 
final Pattern p = Pattern.compile(re); 

System.out.println(p.asPredicate().test(input)); // false 

Scanner s = new Scanner(input); 
System.out.println(s.hasNext(p)); //false 
s.close();