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)); }