Wiki ~ namok.be

Classe Scanner

Notion de token

Un “scanner”, fournit par la classe Scanner, permet de parser une chaine de caractères. Cette chaine peut-être fournie sur l'entrée standard par exemple.

Scanner clavier = new Scanner(System.in) ; 
Scanner uneEntrée = new Scanner("La réponse est 42") ;

Cette chaine de caractère est décomposée en token. Un token est un élément particulier. Par défaut le séparateur de token est le Whitespace (ce séparateur peut être modifié par la méthode useDelimiteur, voir la doc)

Si mon scanner recoit la chaine “Hello world”, il fournira deux tokens; “hello” et “world” (à condition que je les demande via la méthode next())

Lecture au clavier, nextInt et consorts

Comme dit plus haut, le scanner fournit des tokens. Chaque token peut être convertit en un certain type via la méthode next adéquate.

Ainsi nextInt() transformera le token “43” (qui est de type String) en le nombre entier (de type int) 42.

A chaque type (ou presque) correspond une méthode next idoine.

Quel différence entre next() et nextLine() ?

next() retourne le token suivant sous la forme d'un String, tandis que nextLine() retourne la chaine jusqu'à la fin de la ligne (elle lit la fin de ligne mais ne l'inclut pas dans la chaine lue). Cette chaine peut donc contenir des séparateurs (Whitespace par défaut).

Cas particulier de la lecture d'un seul caractère

La classe Scanner n'offre pas de méthode nextChar ou nextCharacter. Pour lire un caractère, il faudra lire une chaine (un String) et ensuite ne retenir que le premier caractère de la chaine.

Si s est le String lu, on aura quelque chose du style

char c = s.charAt(0); 

Il est également possible d'imposer un format de lecture en utilisant la méthode next(String pattern) de la classe Scanner. Dans ce cas, le scanner retourne le token vérifiant le pattern s'il existe sinon, il jette une exception (qu'il faudra traiter).

Par exemple pour imposer une token d'une seule lettre parmi {h, H, f, F}, on peut écrire

Scanner clavier = new Scanner("h") ;  // ou "H" ou "f" ou "F" 
				      //sinon jette exception
String s = clavier.next("[HhFf]") ;
System.out.println("Lecture: " + s);	// Ecrit "Lecture: h
char c = s.charAt(0) ; 			// Pour obtenir le char 'h'

Remarque

Comme on l'a déjà dit dans les exemples sur la méthode matches (voir matches), il faut “double échapper” les caractères que l'on “échaperait” simplement dans une expression régulière.

Par exemple pour lire les opérateurs, +, -, * et /, il faut échapper les caractères ayant un sens particulier (*, + et -) … (voir doc sur les régex)

clavier.next("[\\+\\-\\*/]") ; 

Y-a-t'il quelque chose à lire ?

La classe Scanner fournit aussi toute une série de méthodes de la forme hasNext() permettant de savoir si le scanner possède un token en entrée. Ceci permet une structure du type

...
while ( clavier.hasNext() ) {
	chaineLue = clavier.nextLine() ; 
	// traitement de la chaine
}

Notion de Locale

Par défaut un scanner prend le locale propre au système .. mais on peu en déterminer un autre.

Un locale est un objet représentant une région au sens politique, géographique et/ou culturel. Cet objet détermine un certain comportement propre aux habitudes … locales; les francais utilisent des accents, les anglais pas et les allemands les utilisent différemment que les belges …

Lorsque l'on traite des nombres, la classe Scanner s'adapte aux habitudes locales (c'est-à-dire celles du système) afin de ne pas perturber l'utilisateur … et elle pense (à bon escient) que nous utilisons la virgule comme séparateur décimal, etc.

Hors nous voulons parfois (souvent) encoder nos nombres “à l'anglaise”. C'est-à-dire avec un point décimal (et pas une virgule). Il suffit de le dire à notre scanner … on écrira dans ce cas quelque chose du style

Scanner clavier = new Scanner(System.in) ; 
clavier.useLocale(Locale.UK) ; 

TODO Belle structure de lecture

Je propose la structure suivante. Elle a l'avantage d'être à la fois concise et proche de la version sans vérification des données car il suffit d'insérer un bout de code sans toucher au code existant.

    System.out.println( "Message d'invite" );
    while( !clavier.hasNextInt() ) {
      System.out.println( "Message d'erreur" );
      clavier.next();
    }
    int n = clavier.nextInt();