pdf 2

Transcription

pdf 2
Les expressions régulières en java
Ce document explique comment utiliser les expressions régulières en
java. Il s’inspire de la documentation de la classe Pattern sur le site
d’oracle.
Qu’est ce qu’une expression régulière ?
Une expression régulière ou rationnelle est une chaine de caractères
qui décrit un ensemble de chaines de caractères.
Par exemple l’expression régulière [0-9][a-z] décrit l’ensemble des
chaines de caractères composées d’un chiffre et d’une lettre.
A quoi servent les expressions régulières ?
Les expressions régulières ont de nombreuses utilités en informatique,
elles servent principalement pour réaliser :
•
des filtres : ne conserver que certaines lignes d’un fichier texte
: par exemples que les lignes de la forme variable=valeur.
•
des contrôles : vérifier qu’une donnée entrée par un utilisateur
a bien le format d’une adresse ip par exemple.
•
des substitutions : remplacer un motif par une chaine de
caractères précise : par exemple, remplacer les majuscules par des
minuscules.
•
des découpages : récupérer une partie d’une chaine de
caractères par exemple une date placée dans une chaine de
caractères. Ou bien découper une ligne par rapport aux « ; » dans le
cas d’un fichier .csv.
Créer une expression régulière
Pour créer une expression régulière en java, on respecte une certaine
syntaxe qui est décrite dans la documentation officielle sur le site
d’oracle : classe Pattern. Je décris ci-dessous les principaux caractères
utilisés.
Composantes d’une expression régulières
Les caractères
X
Le caractère X
\\
Le caractère \
\t
Le caractère tabulation
\n
Le caractère nouvelle ligne
\r
Le caractère retour chariot
\f
Le caractère saut de page
Exemple : AB\tCD représente la chaine de caractère AB suivi d’une
tabulation suivi de CD.
Les classes de caractères
[abc]
Les caractères a, b ou c
[^abc]
Les caractères qui ne sont pas a, b ou c
[a-z]
Un caractère de a à z
[a-zA-Z]
Un caractère de a à z minuscule ou majuscule
[0-9]
Un caractère numérique
Exemple : [0-9][a-z] représente une chaine de caractères constituée
d’un chiffre puis d’une lettre.
Il faut noter qu’il existe une différence entre ab qui représente la
chaine de caractère « ab » de [ab] qui représente soit la chaine de
caractère « a » soit la chaine de caractères « b ».
Les classes de caractères prédéfinies
.
Un caractère quelconque
\d
Un caractère numérique : [0-9]
\D
Un caractère non numérique : [^0-9]
\s
Un carctère blanc : [ \t\n\x0B\f\r]
\S
Un caractère non blanc : [^\s]
Classes de caractères POSIX
\p{Lower}
Une misnuscule : [a-z]
\p{Upper}
Une majuscule :[A-Z]
\p{Alpha}
Un caractère alphabétique : [\p{Lower}\p{Upper}]
\p{Digit}
Un chiffre : [0-9]
\p{Alnum}
Un caractère alphanumérique : [\p{Alpha}\p{Digit}]
\p{Punct}
Ponctionation : !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
\p{Blank}
Espace ou tabulation : [ \t]
\p{XDigit}
Un caractère hexadécimal: [0-9a-fA-F]
\p{Space}
Un caractère blanc : [ \t\n\x0B\f\r]
Les caractères de répétition
X?
X une fois ou zéro fois
X*
X zéro ou plusieurs fois
X+
X une fois au moins (XX*)
X{n}
X n fois
X{n,}
X, au moins n fois
X{n,m}
X entre n et m fois
Opérateurs logiques
XY
X suivi de Y
X|Y
X ou Y
Exemples
Expression régulière correspondant à une adresse IP
Une adresse IP est de la forme suivante : 255.255.0.1 ou bien
127.0.0.1, son format est donc :
Un à trois chiffres, point, un à trois chiffres, point, un à trois chiffres,
point, un à trois chiffres.
L’expression régulière correspondante est donc :
[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}
ou
\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}
On peut également utiliser une expression régulière plus simple si on
ne souhaite pas vérifier que le nombre de chiffres est bien compris
entre un et trois :
\d+\.\d+\.\d+\.\d+
Remarque : Le point s’écrit \. car « . » est un caractère qui signifie «
un caractère quelconque ». Le \ précédent le . sert à indiquer qu’il ne
faut pas interpréter le point comme une expression régulière.
Expression régulière correspondant à une date
Une date au format 29 février 2012 suit le motif suivant :
Un ou deux chiffres, un espace, un nombre indéfini de lettres, un
espace puis quatre chiffres.
L’expression régulière associée est donc :
[0-9]{1,2} [a-z]+ [0-9]{4}
ou
\d{1,2} \p{Lower}+ \d{4}
Expression régulière d’une ligne de la commande dir
La commande dos « dir » permet de lister les fichiers d’un répertoire.
La sortie de cette commande se présente sous la forme suivante :
26/01/2012 11:45 <REP> dossier
26/01/2012 11:45 fichier.txt
Le format est donc : la date suivie de plusieurs espaces, suivie de
l’heure, suivie de plusieurs espaces, ensuite, si le fichier est un
dossier, on trouve la chaine de caractère <REP> et rien sinon, et pour
finir, le nom du fichier ou du dossier.
L’expression régulière correspondante est
\d{1,2}/\d{1,2}/\d{1,2}\p{Space}*\d{1,2}
:\d{1,2}\p{Space}*\p{Upper}*\p{Space}*\p{Alpha}*
Utilisation avec java
Une première remarque est que le caractère \ a un sens pour java, il
faut donc le doubler dans l’écriture des expressions régulières pour
qu’il ne soit pas interprété par java. Par exemple, on écrira \\. à la
place de \.
Les méthodes
La méthode matches de la classe String
public boolean matches(String regex)
La méthode matches de la classe String permet de savoir si une chaine
de caractère respecte une expression régulière. Pour cela, on passe
l’expression régulière en paramètre de la méthode et la méthode
retourne true si l’expression régulière est vérifiée par la chaine de
caractères.
La méthode replaceAll de String
public String replaceAll(String regex, String replacement)
La méthode replaceAll permet de remplacer toutes les occurrences
d’une expression régulière par une expression de remplacement. Cette
méthode peut être également appelée en utilisant la méthode
replaceAll de la classe Pattern (ici str est le chaine sur laquelle on
recherche
:
Pattern.compile(regex).matcher(str).replaceAll(replacement).
La méthode split de la classe String
public String[] split(String regex)
La méthode split permet de découper une chaine de caractères en
fonction d’une expression régulière. Le résultat du découpage est
retourné dans un tableau.
Si le découpage est fait à l’aide d’un unique caractère (souvent espace
ou « ; ») on utilisera plutôt la classe StringTokenizer qui ne permet
pas l’utilisation des expressions régulières.
Exemples
Réaliser des filtres
On peut vouloir ne conserver que certaines lignes d’un fichier texte,
par exemple si on veut lire le fichier etc/hosts qui contient les
correspondances entre les noms d’hôtes et les adresses IP des
machines.
Ce fichier peut contenir des commentaires qui sont précédés du
caractère #. On pourrait donc penser qu’il suffit de récupérer le
premier caractère de la ligne et de le comparer à ‘#’ mais, ce n’est pas
si simple.
Une ligne est un commentaire si et seulement si le premier caractère
non blanc est un #. Pour s’en sortir sans les expressions régulières, il
faudrait donc coder une fonction avec des boucles imbriquées qui
serait assez longues et complexes. Une ligne suffit si on utilise les
expressions régulières.
Admettons que nous ayons récupéré le contenu du fichier dans une
ArrayList et qu’on souhaite extraire une liste contenant uniquement les
lignes qui ne sont pas des commentaires :
public static void main(String[] args){
List<String> listeInitiale = new ArrayList<String>();
listeInitiale.add("#
source");
102.54.94.97
rhino.acme.com
#
serveur
listeInitiale.add(" # 38.78.63.10 x.acme.com # hôte client x");
listeInitiale.add("");
listeInitiale.add("127.0.0.1 localhost # machine courante");
for(String s : listeInitiale){
if(!s.matches("\\p{Space}*[#].*") && s.length()>0)
System.out.println(s);
}
}
Réaliser des contrôles
Pour vérifier qu’un champ correspond bien à une adresse ip, on peut
utiliser la méthode matches de String comme dans l’exemple
précédent
public static void main(String[] args){
String champ = "255.255.10.1";
System.out.println(champ.matches("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}
\\.\\d{1,3}"));
}
Réaliser des substitutions
Si on veut remplacer tout les espaces multiples d’un fichier par un seul
espace, on peut utiliser la méthode rempaceAll avec l’expression
régulière \\p{Space}+
public static void main(String[] args){
String test = "1 2 3 4 5
6 7 8 ";
System.out.println(test.replaceAll("\\p{Space}+", " "));
}
Réaliser des découpages de chaines
Pour découper une chaine selon une expression régulière, on utilise la
méthode split de la classe String.
Par exemple, si on a un fichier chaque ligne est constituée de
différentes informations séparées par une suite de caractères par
exemple !@!, ont peut utiliser la méthode split pour récupérer toutes
les informations séparément dans un tableau.
Par exemple :
public static void main(String[] args){
String test = "Jean Pierre!@!Paul!@!45";
String[] infos = test.split("!@!");
System.out.println("Nom : "+infos[1]+"\nPrénom : "+infos[0]);
}
Récupérer une information dans une chaine
On peut récupérer une information présente dans une chaine de
caractère en utilisant les « capturing groups ».
Le principe est simple : il suffit de places des parenthèses autour de la
sous expression régulière que l’on souhaite récupérer.
Par exemple : on souhaite récupérer les noms de tous les processus
qui s’exécutent sur une machine. Pour cela on lance la commande Dos
TASKLIST qui nous donne des informations sur les processus de la
manière suivante :
Nom de l'image PIDÿ Nom de la sessio Num‚ro d Utilisation
====================== ==== ================
======== ============
System Idle Process 0 Console 0 28 Ko
System 4 Console 0 44 Ko
smss.exe 732 Console 0 60 Ko
csrss.exe 796 Console 0 3ÿ564 Ko
winlogon.exe 820 Console 0 6ÿ456 Ko
services.exe 864 Console 0 3ÿ772 Ko
On pourrait récupérer les informations en utilisant le fait que le nom
de l’image ne peut pas être plus ongue que 24 caractères. Mais nous
allons plutôt utiliser une expression régulière avec capturing group.
L’expression régulière qui décrit cette ligne est :
[^0-9]+\\p{Space}+[0-9]+.*
On souhaite récupérer la partie [0-9]+, on va donc placer des
parenthèses autour de cette partie et utiliser les méthodes de la classe
Pattern pour récupérer le nom de l’image.
public static String recupererNomImage(String ligne){
String res="";
String patternStr = "([^0-9]+)\\p{Space}+[0-9]+.*";
Pattern pattern = Pattern.compile(patternStr);
Matcher matcher = pattern.matcher(ligne);
boolean matchFound = matcher.find();
if (matchFound && matcher.groupCount()>=1) {
res = matcher.group(1);
}
return res;
}
public static void main(String[] args) {
String test="System Idle Process 0 Console 0 28 Ko";
System.out.println(recupererNomImage(test));
}