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.
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.
Les expressions régulières ont de nombreuses utilités en informatique, elles servent principalement pour réaliser :
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.
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.
[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 ».
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 *
\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 *
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
XY X suivi de Y
X|Y X ou Y
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.
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}
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}*
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 \.
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.
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).
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.
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("# 102.54.94.97 rhino.acme.com # serveur source");
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);
}
}
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}"));
}
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}+", " "));
}
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]);
}
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 :
Nomde l'image | PID | Nom de la session | Numéro d'utilisation | 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 | 3564 Ko |
winlogon.exe | 820 | Console | 0 | 6456 Ko |
services.exe | 864 | Console | 0 | 3772 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));
}