• Aucun résultat trouvé

9.5 Expressions r´eguli`eres

9.5.1 Principe

Le lecteur est suppos´e connaˆıtre par ailleurs la notion d’expression r´eguli`ere, dont l’explication, mˆeme succincte, d´epasserait le cadre de ce cours. Disons simplement que les expressions r´eguli`eres consid´er´ees ici sont grosso modo celles du langage Perl59, et donnons quelques exemples montrant leur utilisation en Java.

Le paquetage concern´e, java.util.regex, se compose des deux classes Pattern et Matcher : Pattern - Un objet de cette classe est la repr´esentation compil´ee 60 d’une expression r´eguli`ere.

Cette classe n’a pas de constructeur. On cr´ee un objet Pattern par une expresion de la forme : Pattern motif = Pattern.compile(texteExpReg [, flags ]) ;

o`u texteExpReg est une chaˆıne de caract`eres contenant l’expression r´eguli`ere. Si cette derni`ere est incorrecte, l’instruction ci-dessus lance une exception PatternSyntaxException, qui est une sous- classe de RuntimeException61.

Matcher - Un objet de cette classe se charge d’appliquer une expression r´eguli`ere sur un texte, pour effectuer les op´erations de reconnaissance, de recherche ou de remplacement souhait´ees.

On cr´ee un objet Matcher `a partir d’un objet Pattern, par une expression de la forme : Matcher reconnaisseur = motif .matcher(texteAExaminer ) ;

L’objet reconnaisseur ainsi cr´e´e dispose des m´ethodes :

boolean matches() : l’expression r´eguli`ere reconnaˆıt-elle la totalit´e du texte `a examiner ? boolean lookingAt() : l’expression r´eguli`ere reconnaˆıt-elle le d´ebut du texte `a examiner ? boolean find([int start]) : l’expression r´eguli`ere reconnaˆıt-elle un morceau du texte `a exami- ner ?

A la suite d’un appel d’une des trois m´ethodes ci-dessus, les m´ethodes int start() et int end() de l’objet Matcher renvoient le d´ebut et la fin de la sous-chaˆıne reconnue, tandis que la m´ethode String group() renvoie la chaˆıne reconnue elle-mˆeme.

On se reportera `a la documentation de l’API pour des explications sur les (nombreuses) autres possi- bilit´es de la classe Matcher.

9.5.2 Exemples

1. D´ecouper un texte. Pour les op´erations les plus simples il n’y a pas besoin de cr´eer des objets Matcher, des m´ethodes ordinaires (exemple 1) ou statiques (exemple 2) de la classe Pattern suffisent. Par exemple, le programme suivant prend une chaˆıne donn´ee en argument et l’affiche `a raison d’un mot par ligne, en consid´erant que les s´eparateurs de mots sont la virgule ( , ), le point-virgule ( ; ) et les caract`eres blancs de toute sorte (collectivement repr´esent´es par \s ) :

59La syntaxe pr´ecise des expressions r´eguli`eres accept´ees par Java est donn´ee dans la documentation de l’API, au d´ebut de

l’explication concernant la classe java.util.regex.Pattern

60On peut penser qu’un objet Pattern consiste essentiellement en l’encapsulation des tables qui d´efinissent l’automate d’´etats

fini correspondant `a ’expression r´eguli`ere donn´ee.

61Rappelons que les RuntimeException sont des exceptions non contrˆol´ees. Par cons´equent, si une m´ethode contient des appels

9 QUELQUES CLASSES UTILES 9.5 Expressions r´eguli`eres

import java.util.regex.Pattern; public class Mots {

public static void main(String[] args) {

Pattern motif = Pattern.compile("[,;\\s]+"); // d´ecoupe de la cha^ıne args[0] en mots String[] tabMots = motif.split(args[0]); for (int i = 0; i < tabMots.length; i++)

System.out.println(tabMots[i]); }

}

Exemple d’utilisation :

$ java Mots "Andr´e, B´eatrice Caroline, Emile" Andr´e

B´eatrice Caroline Emile $

2. V´erifier la correction d’une chaˆıne. Une autre op´eration simple qu’une m´ethode statique de la classe Pattern peut effectuer sans l’aide d’un objet Matcher : compiler une expression r´eguli`ere et d´eterminer si elle correspond `a la totalit´e d’une chaˆıne donn´ee.

Par exemple, la m´ethode suivante d´etermine si la chaˆıne pass´ee en argument est l’´ecriture correcte d’un nombre d´ecimal en virgule fixe :

boolean bienEcrit(String texte) {

final String expr = "[+-]?[0-9]+(\\.[0-9]*)?";

// texte appartient-il `a l’ensemble de mots d´efini par expr ? return Pattern.matches(expr, texte);

}

Note 1. Cette m´ethode donne pour bonnes des chaˆınes comme "12.3", "123." et "123", mais rejette ".123". Pour corriger cela il suffit de d´efinir expr comme ceci :

final String expr = "[+-]?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))";

Note 2. Dans le cas o`u la m´ethode pr´ec´edente est susceptible d’ˆetre fr´equemment appel´ee, il est ma- nifestement maladroit de compiler chaque fois la mˆeme expression r´eguli`ere. L’emploi d’un objet Pattern permet d’´eviter cela :

Pattern pattern = Pattern.compile("[+-]?[0-9]+(\\.[0-9]*)?"); boolean bienEcrit(String texte) {

return pattern.matcher(texte).matches(); }

3. Recherches multiples. Le programme suivant extrait les liens contenus dans une page html (repr´esent´es par des balises comme <a href="http://www.luminy.univ-mrs.fr" ... >) :

import java.io.*;

import java.util.regex.*; public class TrouverURL {

public static void main(String[] args) { String texte;

try {

File fichier = new File(args[0]);

char[] tampon = new char[(int) fichier.length()]; Reader lecteur = new FileReader(fichier);

lecteur.read(tampon); lecteur.close();

texte = new String(tampon); } catch (IOException e) {

e.printStackTrace(); return;

}

String expReg = "<a[ \\t\\n]+href=\"[^\"]+\"";

Pattern motif = Pattern.compile(expReg, Pattern.CASE_INSENSITIVE); Matcher recon = motif.matcher(texte);

int pos = 0;

while (recon.find(pos)) {

String s = texte.substring(recon.start(), recon.end()); System.out.println(s);

pos = recon.end(); }

} }

Ce programme affiche des lignes de la forme <a href="MonSoft.html"

<a href="Polys/PolyJava.html" ...

<a href="http://www.luminy.univ-mrs.fr/" <a href="mailto:garreta@univmed.fr"

On peut extraire des informations plus fines, en utilisant la notion de groupe de capture des expressions r´eguli`eres. Voici les seules modifications `a faire dans le programme pr´ec´edent :

public class TrouverURL { ...

String expReg = "<a[ \\t\\n]+href=\"([^\"]+)\"";

...

String s = texte.substring(recon.start(1), recon.end(1));

...

}

L’affichage est maintenant comme ceci (magique, n’est-ce pas ?) : MonSoft.html

Polys/PolyJava.html ...

http://www.luminy.univ-mrs.fr/ mailto:garreta@univmed.fr

4. Remplacer toutes les occurrences. Le programme suivant remplace les occurrences du mot chat par le mot chien62. Appel´e avec l’argument ”un chat, deux chats, trois chats dans mon jardin” il affiche

donc la chaˆıne un chien, deux chiens, trois chiens dans mon jardin.

9 QUELQUES CLASSES UTILES 9.5 Expressions r´eguli`eres

Notez que c’est recon, l’objet Matcher, qui prend soin de recopier dans la chaˆıne sortie les caract`eres qui se trouvent entre les occurrences du motif cherch´e :

public static void main(String[] args) throws Exception { Pattern motif = Pattern.compile("chat");

Matcher recon = motif.matcher(args[0]); StringBuffer sortie = new StringBuffer(); while(recon.find())

recon.appendReplacement(sortie, "chien"); recon.appendTail(sortie);

System.out.println(sortie.toString()); }

L’exemple ci-dessus a ´et´e r´edig´e comme cela pour illustrer les m´ethodes appendReplacement et appendTail. On notera cependant que, s’agissant de remplacer toutes les occurrences d’un motif par une chaˆıne, il y a un moyen plus simple :

public static void main(String[] args) throws Exception { Pattern motif = Pattern.compile("chat");

Matcher recon = motif.matcher(args[0]); String sortie = recon.replaceAll("chien"); System.out.println(sortie);

10

Threads

L’´etude des threads est `a sa place dans un cours sur la programmation parall`ele et sort largement du cadre de ce polycopi´e. Nous nous limitons ici `a donner quelques explications sur certaines notions basiques auxquelles on est confront´e dans les applications les plus courantes, par exemple lorsqu’on programme des interfaces utilisateur graphiques.

Un thread, ou processus l´eger, est l’entit´e constitu´ee par un programme en cours d’ex´ecution. Cela se mat´erialise par un couple (code, donn´ees) : le code en cours d’ex´ecution et les donn´ees que ce code traite. Si on en parle ici c’est que Java supporte l’existence simultan´ee de plusieurs threads : `a tout instant, plusieurs programmes peuvent s’ex´ecuter en mˆeme temps.

Ce que en mˆeme temps  veut dire exactement d´epend du mat´eriel utilis´e. Dans un syst`eme poss´edant plusieurs processeurs il est possible que divers threads s’ex´ecutent chacun sur un processeur distinct et on est alors en pr´esence d’un parall´elisme vrai. Mais, plus couramment, les syst`emes ne disposent que d’un unique processeur et il faut se contenter d’un parall´elisme simul´e : les divers threads existant `a un instant donn´e disposent du processeur `a tour de rˆole.

Diff´erentes raisons peuvent faire qu’un thread qui est en train d’utiliser le processeur le c`ede `a un autre thread qui patiente pour l’avoir :

1) le blocage du thread actif par une op´eration ad hoc comme wait (attendre) ou sleep (dormir), 2) le blocage du thread actif par le fait qu’il entame une op´eration d’entr´ee-sortie63,

3) le d´eblocage d’un thread ayant une priorit´e sup´erieure `a celle du thread actif, 4) l’´epuisement d’une certaine tranche de temps allou´ee au thread actif.

Si tout thread cesse d’ˆetre actif d`es qu’un thread de priorit´e sup´erieure est prˆet (cas 3, ci-dessus) on dit qu’on a affaire `a un parall´elisme pr´eemptif. La machine Java proc`ede g´en´eralement ainsi.

Le fonctionnement par attribution de tranches de temps (cas 4) ne fait pas partie des sp´ecifications de la machine Java. Celle-ci en b´en´eficie ou non, selon les caract´eristiques du mat´eriel sous-jacent.

10.1

Cr´eation et cycle de vie d’un thread

10.1.1 D´eclaration, cr´eation et lancement de threads