====== Classe Scanner======
=====Notion de token=====
Un "scanner", fournit par la classe //[[sunUtil>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 [[esi:javaexempleselementaires#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 [[javaUtil>locale]] propre au système .. mais on peu en
déterminer un autre.
Un [[javaUtil>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 [[javaUtil>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();