Les expressions rationnelles sont un outil d’analyse de texte par un ordinateur. Elles permettent de décrire des enchaînements de caractères d’une complexité suffisamment grande pour être réellement utiles, mais suffisamment faible pour être implémentées efficacement. Elles sont d’une importance capitale pour le théoricien des langages comme pour l’UNIX power user.
Dans cette dépêche, nous :
- décrivons brièvement la notion abstraite d’expression rationnelle et recensons les implémentations les plus courantes sur un système Unix ;
- présentons quelques commandes permettant de rechercher des motifs décrits par une expression rationnelle dans un texte, réécrire des fichiers automatiquement ou transformer et analyser des fichiers structurés automatiquement en utilisant des expressions rationnelles ;
- montrons comment améliorer votre productivité avec Emacs grâce aux expressions rationnelles.
Dans cette dépêche, nous allons nous pencher sur les expressions rationnelles (souvent nommées abusivement expressions régulières suite à une traduction littérale de regular expression). Elles permettent de représenter formellement un motif de recherche, par exemple : un caractère alphabétique majuscule suivi de quatre caractères minuscules, puis deux chiffres et un point à la fin. Les expressions rationnelles représentent un outil puissant pour qui sait les utiliser à bon escient mais nécessitent une phase d’apprentissage non négligeable. La diversité des moteurs et des syntaxes n’aide pas non plus à leur simplicité, et les confusions entre les différents outils peuvent parfois donner des résultats surprenants.
Sommaire
- Description abstraite et implémentations principales
- Les expressions rationnelles POSIX basiques
- Extension des expressions rationnelles
- Pour aller plus loin
Source : original en VO XKCD, traduction en VF
Description abstraite et implémentations principales
Les expressions rationnelles sont souvent utilisées comme brique de l’analyse des textes, pour faire de l’analyse lexicale. Elles sont issues des théories mathématiques des langages formels.
Le concept ayant montré sa pertinence, il faut faire face à une richesse des implémentations : POSIX, puis chaque Unix à sa version, GNU, FreeBSD, puis Perl et Emacs, pour les plus répandues. Certaines apportent des extensions (sucre syntaxique +, répétitions, groupes, et back tracking).
Wikipédia fournit divers exemples illustratifs. En voici quelques exemples variés :
- recherche de motif avec
grep
pour avoir un filtre pour sélectionner des lignes, pour identifier des fichiers, pour sélectionner des journaux système à une certaine date ou pour rechercher dans les pages de manuel, etc. ; - avec
sed
, transformation de journaux système en format Apache en format tabulaire, transformation de la sortie de Docker, ps, etc. ; - dans
Emacs
, mettre en valeur un motif dans du code pour une revue ou pour l’édition, extraire des listes d’un fichier avec re-search, etc.
Les expressions rationnelles POSIX basiques
Les expressions rationelles POSIX génèrent des machines à état fini déterministe. Elles ne sont ainsi pas capables de faire des retours en arrière.
La commande grep
Le premier usage des expressions rationnelles pour les utilisateurs de systèmes basés sur GNU/Linux ou Unix est en général la commande grep
, qui permet de trouver toutes les lignes correspondant à une expression rationnelle. La syntaxe de la commande grep
est simplement :
grep <options> <expression rationnelle> <liste de fichiers>
Pour les exemples ci‐dessous, nous ferons des recherches dans le fichier french d’une Debian stable (paquet wfrench qui amène le fichier /usr/share/dict/french
, [informations de licence]), ce fichier contenant la liste des mots de la langue française à raison d’un mot par ligne.
Dans une expression rationnelle, la première règle est que chaque caractère se représente lui‐même, par exemple l’expression rationnelle « rationnelle
» correspond à « toute ligne contenant un r, suivi d’un a, suivi d’un t, suivi d’un i, suivi d’un o, suivi d’un n, suivi d’un autre n, suivi d’un e, suivi d’un l, suivi d’un autre l, suivi d’un e, suivi d’un s » :
Chaque caractère ne représente pas vraiment lui‐même, il existe des exceptions avec des méta‐caractères qui décrivent autre chose qu’eux‐mêmes. Un des plus utilisés de ces méta‐caractères est le point, qui signifie « un caractère quelconque », par exemple l’expression rationnelle « rationnelle.
» correspond à « toute ligne contenant un r, suivi d’un a, suivi d’un t, suivi d’un i, suivi d’un o, suivi d’un n, suivi d’un autre n, suivi d’un e, suivi d’un l, suivi d’un autre l, suivi d’un e, suivi d’un caractère quelconque » :
Le problème des méta‐caractères est qu’on peut vouloir chercher du texte les contenant. Par exemple, dans notre dictionnaire, il y a des abréviations se terminant par un point. Pour qu’un méta‐caractère ne soit pas interprété, il faut le précéder d’une contre‐oblique « \ », par exemple « \. » représente le caractère point. On peut alors s’amuser à chercher les abréviations d’au moins six caractères, en les décrivant comme « un caractère quelconque, suivi d’un autre caractère quelconque, suivi d’un troisième caractère quelconque, suivi d’un quatrième caractère quelconque, suivi d’un cinquième caractère quelconque, suivi d’un sixième caractère quelconque, suivi d’un point » :
On remarquera que le point lui‐même est un caractère quelconque.
Un autre méta‐caractère utile est le crochet, qui permet de décrire un caractère pouvant correspondre à plusieurs valeurs, par exemple une voyelle non accentuée peut être représentée par « [aeiouy]
» (qu’on peut lire comme « n’importe quel caractère étant soit un a, soit un e, soit un i, soit un u, soit un y »). Par exemple, si vous voulez briller en société en citant des mots comportant six voyelles non accentuées à la suite :
Deux méta‐caractères particuliers sont utiles entre crochets :
- le tiret situé entre deux caractères permet de définir une liste de caractères qui se suivent, par exemple «
[a-f]
» définit « soit un a, soit un b, soit un c, soit un d, soit un e, soit un f » ; - l’accent circonflexe situé au début permet de définir une exclusion de caractères, par exemple «
[\^aeiouy]
» définit « un quelconque caractère qui ne soit ni un a, ni un e, ni un i, ni un o, ni un u, ni un y »). Ces deux méta‐caractères sont cumulables, par exemple «[\^a-z]
» définit « un quelconque caractère qui ne soit pas une lettre minuscule non accentuée », ce qui peut nous permettre de trouver tous les mots qui ont à la suite deux caractères qui ne sont pas des lettres :
On peut économiser les copier‐coller lorsque l’on veut chercher plusieurs fois la même information, en utilisant le symbole « \{min,max\}
» qui permet d'indiquer que l’on cherche la présence d’un caractère successivement entre min et max fois, par exemple si vous cherchez les mots contenant deux q séparés par 5 à 7 lettres [1] :
Il est possible avec certaines versions de grep de spécifier un seul chiffre entre accolades :
- si l’on cherche exactement x occurrences, on indique : «
\{x\}
» ; - si l’on cherche de 0 à x occurrences, on indique : «
\{,x\}
» ; - si l’on cherche au moins x occurrences, on indique : «
\{x,\}
». Ainsi, on pourrait donc abréger la recherche des mots contenant 6 voyelles non accentuées ainsi :
Si l’on veut répéter plusieurs caractères au lieu d’un seul, il faut encadrer la recherche avec des « \( \)
». Par exemple, si vous bloquez dans une grille de mots croisés sur la définition « mot contenant sept fois à la suite une consonne suivie d’une voyelle » :
Le contenu trouvé à partir d’une expression entre parenthèses est dit « capturé », cela signifie qu’il est gardé en mémoire et peut être réutilisé dans l’expression rationnelle. La contenu capturé est accessible en utilisant « \1
», « \2
», « \3
», etc. (en général, on ne peut pas dépasser \9
). Le numéro de capture est défini en comptant le nombre de parenthèses ouvrantes précédant l’expression capturée. Cela permet par exemple de lister les mots contenant un palindrome de quatre lettres :
On peut encore affiner les recherches en utilisant les ancres, qui permettent de situer où se situe une expression rationnelle dans la ligne :
- le dollar, lorsqu’il est situé à la fin de l’expression rationnelle, représente la fin de la ligne ;
- l’accent circonflexe, lorsqu’il est situé au début de l’expression rationnelle, représente le début de la ligne.
On peut cumuler les deux ancres dans la même expression, par exemple si l’on veut chercher les vrais palindromes de quatre lettres :
Pour en terminer avec les expressions rationnelles POSIX basiques, il ne reste plus qu’un méta‐caractère à présenter, qui est l’astérisque. Ce caractère est équivalent à « \{0,\}
» :
Utiliser dans vi
VimRegex détaille largement le sujet.
Extension des expressions rationnelles
Les extensions rationnelles basiques étant peu lisibles, la norme POSIX a évolué pour intégrer les expressions rationnelles étendues, aussi appelées « ERE ».
grep est mieux avec « -E »
Les versions récentes de grep
permettent d’utiliser les expressions rationnelles étendues avec l’option -E
. Si vous ajoutez l’option -E
à grep
, vous devez modifier votre expression rationnelle ainsi :
-
\{
et\}
deviennent{
et}
; -
\(
et\)
deviennent(
et)
; - tous les autres méta‐caractères («
.
», «[
», «]
», «-
», «^
», «$
», «*
», «\1
», etc.) sont inchangés.
Outre cette suppression des contre‐obliques superflus, les expressions rationnelles étendues apportent trois nouveaux méta‐caractères. Le premier est « ?
» qui est un synonyme de « {0,1}
», qui permet par exemple de chercher les palindromes de 4 ou 6 lettres avec une seule expression :
On dispose aussi de « +
» qui est un synonyme de « {1,}
» :
Enfin, le dernier méta‐caractère spécifique aux expressions rationnelles étendues est le « |
» qui permet de séparer plusieurs options :
Les classes de caractères
POSIX prévoit des classes de caractère, qui sont des notations spécifiques entre crochets. À noter que les classes de caractères sont aussi bien gérées par les expressions rationnelles basiques qu’étendues (il n’y a donc pas besoin d’utiliser l’option -E
pour en bénéficier), mais il existe des implémentations d’expressions rationnelles basiques non compatibles POSIX qui ne les acceptent pas.
Les classes de caractères sont des mots ou abréviations en anglais désignant ce à quoi ils correspondent et encadrés par « [:
» et « :]
» :
-
[:digit:]
: désigne un chiffre décimal (équivalent à[0-9]
) ; -
[:lower:]
: désigne une lettre minuscule (équivalent à[a-z]
) ; -
[:upper:]
: désigne une lettre majuscule (équivalent à[A-Z]
) ; -
[:alpha:]
: désigne une lettre minuscule ou majuscule (équivalent à[A-Za-z]
) ; -
[:alnum:]
: désigne une lettre minuscule ou majuscule ou un chiffre (équivalent à[A-Za-z0-9]
) ; -
[:xdigit:]
: désigne un chiffre hexadécimal (équivalent à [0-9a-fA-F]) ; -
[:space:]
: désigne un caractère d’espacement (espace, tabulation, retour chariot, etc.) ; -
[:blank:]
: désigne un espace ou une tabulation horizontale (à ne pas confondre avec[:space:]
) ; -
[:punct:]
: désigne à un crochet ou un caractère de la classe suivante :['!"#$%&()*+,./:;<=>?@\^_
{|}~-]` ; -
[:cntrl:]
: désigne un caractère de contrôle ; -
[:print:]
: désigne un caractère affichable (ainsi qu’une espace), cette classe est à peu près le contraire de[:cntrl:]
; -
[:graph:]
: désigne l’ensemble des caractères visibles, sauf les espaces, les caractères de contrôle, etc. (équivalent à[\x21-\x7E]
).
Pour aller plus loin
Attention au GLOB
Dans les exemples précédents, il était important d’utiliser de simples apostrophes pour éviter l’interprétation de caractères spéciaux par le Shell.
Outils pour tester vos expressions rationnelles
Plusieurs outils s’offrent à vous pour tester et triturer dans tous les sens vos expressions rationnelles, comme par exemple le site Regex Pal, qui propose notamment de la coloration syntaxique et se veut « temps réel » dans les modifications, ou regex101 qui permet de tester des expressions rationnelles Python, JavaScript ou PCRE.
Ne pas toujours utiliser les expressions rationnelles
Les expressions rationnelles ne sont par exemple pas l’outil idéal pour analyser du XML ou du HTML.
Jouer avec les expressions rationnelles
Voir la dépêche Regexcrossword : un subtil mélange de sudoku et de mots croisés, à la sauce Regex, ainsi que la chasse au trésor du MIT en 2014, etc.
Un peu de théorie
Les automates finis
La base théorique des expressions rationnelles se trouve dans la théorie des langages. Elles permettent notamment de décrire les langages rationnels. Elles sont fortement liées aux automates finis.
Pour illustrer le parallèle nous allons utiliser les caractères et les quantificateurs de base :
-
a
qui permet de reconnaître la lettrea
; -
?
qui permet de définir un groupe optionnel ; -
*
qui permet de définir un groupe se répétant zéro fois ou plus ; -
+
qui permet de définir un groupe se répétant une fois ou plus.
Littérature
- une des ressources en ligne indispensables sur les moteurs d’expressions rationnelles se trouve sur le site de Russ Cox : https://swtch.com/~rsc/regexp/ ;
- un vieil article de Mark‐Jason Dominus explique le fonctionnement des expressions rationnelles et leur application dans Perl ;
- une implémentation expliquée d’un moteur d’expressions rationnelles est disponible dans un cours de l’Université de Vancouver.
[1] Avec ça vous allez vraiment briller en société, il faudra juste trouver un moyen d’intégrer ça dans la conversation.
# Deux outils complementaires pour les devs
Posté par isildur37 . Évalué à 3.
Très bon post!
Pour ceux qui font du ruby il existe rubular pour tester leurs regex, et pour JavaScript j'utilise également scriptular.
Il est à noter également que si en général les admins savent les utiliser, les devs y pensent beaucoup moins, souvent par manque de maîtrise et de formation
[^] # Re: Deux outils complementaires pour les devs
Posté par windu.2b . Évalué à 4.
Il existe aussi des testeurs de regex en ligne, tel que https://regex101.com/
[^] # Commentaire supprimé
Posté par Anonyme . Évalué à 2. Dernière modification le 09 février 2016 à 03:23.
Ce commentaire a été supprimé par l’équipe de modération.
[^] # Re: Deux outils complementaires pour les devs
Posté par zurvan . Évalué à 3.
en outil utile il y a également txt2regex : http://aurelio.net/projects/txt2regex/
Ça permet de construire des regex pour 20 programmes différents (genre Vim, Emacs, Perl, PHP, Python, awk, grep, lisp, mysql, sed…), à partir de questions interactives.
C'est dans les dépôts Debian et dérivés, ou ici : https://github.com/aureliojargas/txt2regex
« Le pouvoir des Tripodes dépendait de la résignation des hommes à l'esclavage. » -- John Christopher
[^] # Re: Deux outils complementaires pour les devs
Posté par nicoxxl . Évalué à 2.
Ne pas oublier l'indispensable https://www.debuggex.com/ !
Qui a l'avantage non négligeable d'avoir un affichage graphique.
# s/(k)(a)(y)(a)(k)/\5\4\3\2\1/
Posté par neilux . Évalué à 4.
Hoho j'étais persuadé que le mot anagramme était masculin. Néanmoins, tu l'utilises pour décrire des palindromes.
[^] # Re: s/(k)(a)(y)(a)(k)/\5\4\3\2\1/
Posté par Benoît Sibaud (site web personnel) . Évalué à 3. Dernière modification le 08 février 2016 à 10:18.
Corrigé, merci (et en plus ça avait été signalé dans la tribune de rédaction de la dépêche
/o\
).[^] # Re: s/(k)(a)(y)(a)(k)/\5\4\3\2\1/
Posté par Anthony Jaguenaud . Évalué à 2.
Dans le chapitre : Attention au GLOB
Il me semble qu’on parle de
'
simple quote, mais les guillemets vont forcément par deux, un peu comme les lunettes.[^] # Re: s/(k)(a)(y)(a)(k)/\5\4\3\2\1/
Posté par Benoît Sibaud (site web personnel) . Évalué à 5.
Pourquoi faire simple… Les guillemets selon Wikipédia :
Sinon j'ai mis apostrophe (aussi appelé guillemet-apostrophe) dans la dépêche.
[^] # Re: s/(k)(a)(y)(a)(k)/\5\4\3\2\1/
Posté par Strash . Évalué à 10.
Mauvais exemple, une lunette est un objet qui existe bel et bien : lunette d'astronomie, lunette d'approche (ou longue-vue)…
# Travailler avec des expressions rationnelles
Posté par reno . Évalué à 6.
C'est jurer comme un charretier car les expressions rationnelles de sed sont différentes de celles de perl, etc.
\+ ??
[^] # Re: Travailler avec des expressions rationnelles
Posté par Benoît Sibaud (site web personnel) . Évalué à 10.
Faut pas faire de SQL (variantes sur les
timestamps
oulimit
par exemple), pas recourir aux regex, pas utiliser d'opérateur d'égalité (on ne sait jamais si c'est =/==/===/eq/… suivant le langage), pas utiliser de nombres multi-octets (little/big endians), pas stocker sur un support disque (placer toujours les données au même endroit ou au contraire éviter pour protéger le support), etc., etc. L'informatique c'est nul :).[^] # Re: Travailler avec des expressions rationnelles
Posté par freem . Évalué à 2.
Voire ne pas utiliser de Bytes tout court, on sait jamais si c'est du 8 bits ou 7 bits, il pourrait y avoir quelques vieilles machines encore en 7bits quelque part sur Terre :)
[^] # Re: Travailler avec des expressions rationnelles
Posté par Tonton Th (Mastodon) . Évalué à 4.
.EQ. is the only true one.
[^] # Re: Travailler avec des expressions rationnelles
Posté par Benoît Sibaud (site web personnel) . Évalué à 6.
Ça m'est égal !
[^] # Re: Travailler avec des expressions rationnelles
Posté par FantastIX . Évalué à 3. Dernière modification le 09 février 2016 à 13:11.
Sous GNU/Linux (au moins):
sed -r
et tout devient plus lisible.
# Ne pas toujours utiliser les expressions rationnelles
Posté par ianux (site web personnel, Mastodon) . Évalué à 5.
Cf. http://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags/1732454#1732454 qui résume plutôt bien la situation.
[^] # Re: Ne pas toujours utiliser les expressions rationnelles
Posté par LupusMic (site web personnel, Mastodon) . Évalué à 3.
Ou même pour les adresses de courrier électroniques, c'est impossible d'écrire une Regex qui prenne en compte l'ensemble des RFC régissant le format des courriels.
[^] # Re: Ne pas toujours utiliser les expressions rationnelles
Posté par StyMaar . Évalué à 2.
C'est pas tout à fait impossible, juste extrêmement difficile d'après cet article de Stéphane Bortzmeyer.
D'après l'article Tom Christiansen l'aurait fait.
[^] # Re: Ne pas toujours utiliser les expressions rationnelles
Posté par KiKouN . Évalué à 5. Dernière modification le 08 février 2016 à 17:41.
En même temps, pondre un truc qui soit difficile à parser via une expression rationnelle, c'est se tirer une balle dans le pied.
Le plus malheureux dans l'histoire, c'est qu'il y a beaucoup de personnes célébres/connues/reconnues qui peuvent voir là où ils marchent.
Ou alors, l'un des gros défauts des expressions rationnelles, c'est de ne pas implémenté de raccourci pour des formats usuels. [:email:] [:ipv6:] par exemple.
Edit : Arfff, note pour plus tard : Lire tout les commentaires avant de répondre à un commentaire : http://linuxfr.org/nodes/105209/comments/1642743
# Outils de coloration?
Posté par StreakyCobra . Évalué à 7.
Quel est l'outil qui t'as permis d'avoir la coloration? Ou est-ce fait à la main?
[^] # Re: Outils de coloration?
Posté par Benoît Sibaud (site web personnel) . Évalué à 4.
Édition manuelle avec LibreOffice d'après la tribune de rédaction de la dépêche
[^] # Re: Outils de coloration?
Posté par StreakyCobra . Évalué à 2.
Zut, un tel outil serait ludique. Merci de l'info.
[^] # Re: Outils de coloration?
Posté par ElectronLibre63 . Évalué à 1.
Il y a l'option color
grep --color …
mais tu n'auras pas un rendu multi-couleurs comme dans les copies d'écran ce-dessus.
[^] # Re: Outils de coloration?
Posté par StreakyCobra . Évalué à 2.
Oui je l'ai déjà celui-là, c'était le côté multi-couleur que je trouvais sympa!
[^] # Re: Outils de coloration?
Posté par El Titi . Évalué à 2.
Atom, mieux que que tous les sites online, avec le surlignage et complètement interactif.
Bon ça ne supporte que les regex JS mais c'est sudffisant pour las usages courants et ok ça n'affiche pas les groups.
Mais quand même !
[^] # Re: Outils de coloration?
Posté par StreakyCobra . Évalué à 6.
Spacemacs me le fait aussi :-)
# Ça manque de classes...
Posté par windu.2b . Évalué à 4. Dernière modification le 08 février 2016 à 11:43.
Un reproche que je ferais aux langages gérant les expressions rationnelles, c'est de ne pas avoir cherché à ajouter de nouvelles classes de caractères, au fur et à mesure des besoins.
Une qui serait fort utile, éviterait de nombreuses erreurs et arrachages de cheveux aux dév, c'est une classe
[:email:]
!Que tous les formulaires du Web sachent enfin gérer, une bonne fois pour toutes, les adresses mails correctement !
Mais j'imaginerais bien aussi des classes
[:ipv4:]
,[:ipv6:]
et[:ip:]
(capable de détecter une IP, qu'elle soit v4 ou v6)…[^] # Re: Ça manque de classes...
Posté par Benoît Sibaud (site web personnel) . Évalué à 10.
Sauf qu'il s'agit de « classes de caractères », pas de vérification de grammaire suivant une RFC.
[:ipv4:]
correspondrait juste à[0-9.]
(mais ça va reconnaître aussi bien 333.444.555.666 que juste 777 ou 0.4).Parce que sinon il suffirait d'avoir [:mot-français-correct:] ou [:commentaire-pertinent-sur-linuxfrorg:] ou [:page-html5:].
[^] # Re: Ça manque de classes...
Posté par freem . Évalué à -1.
Non, ce serait plutôt
([0-9]{1,3}\.){3}[0-9]
, si le {3} fonctionne (peut pas tester d'ici). Par contre pour IP6, ça risque d'être un chouïa plus galère, la notation permettant des raccourcis.Pour ce qui est de l'idée d'ajouter ce type de regex au(x différents) "standard(s)", ça ne ferait que rendre les choses plus complexe, en ajoutant de la fragmentation inutile.
Et puis, ceux qui utilisent souvent les regex doivent s'être fait des listes pour les plus courantes/complexes qu'ils utilisent, non?
[^] # Re: Ça manque de classes...
Posté par flan (site web personnel) . Évalué à 2.
Ta regexp est trop laxiste.
Celle-ci devrait mieux fonctionner : "((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)"
[^] # Re: Ça manque de classes...
Posté par Yves Bourguignon . Évalué à 2.
Pas autant que la tienne, mais il manque une précision sur le dernier octet.
ifconfig | grep -E '([0-9]{1,3}\.){3}[0-9]{1,3}'
inet adr:192.168.1.111 Bcast:192.168.1.255 Masque:255.255.255.0
inet adr:127.0.0.1 Masque:255.0.0.0
Et ça ne suffira pas pour valider une adresse…
echo 256.400.555.999 | grep -E '([0-9]{1,3}\.){3}[0-9]{1,3}'
256.400.555.999
[^] # Re: Ça manque de classes...
Posté par Tonton Th (Mastodon) . Évalué à 3.
Et ça ne suffira pas pour valider une adresse…
Mais bon, qui, à part les plus ultimes des dinos, utilise encore l'octal ?
[^] # Re: Ça manque de classes...
Posté par chimrod (site web personnel) . Évalué à 3.
Tu crois qu'on peut y voir un lien avec le fait de dessiner encore avec PovRay de nos jours ? (-:
[^] # Re: Ça manque de classes...
Posté par freem . Évalué à 2.
Ceux qui cherchent des failles?
[^] # Re: Ça manque de classes...
Posté par freem . Évalué à 2.
Exact, oublié le fait que
[0-9]{1,3}
peut monter jusqu'à 999, ainsi que la typo que j'aie oublié le{1,3}
sur le dernier octet.De ton côté tu as oublié le
\
devant le point :)Sinon, après un test (j'avais testé le comportement avec un 010, vu que je n'ai jamais vu de 0 "inutile" devant un morceau d'IPv4), il semble que ping convertisse les octets depuis l'hexa ou l'octal quand les valeurs sont pré-fixées par 0x ou 0. Du coup, 0xa.10.10.1 semble être une IPv4 valide? Quelqu'un sait?
[^] # Re: Ça manque de classes...
Posté par fearan . Évalué à 3.
une ipv4 c'est
[0-2]?[0-9]{1,2}[.][0-2]?[0-9]{1,2}[.][0-2]?[0-9]{1,2}[.][0-2]?[0-9]{1,2}
ce qui est assez chiant à lire.
my $blocIP="[0-2]?[0-9]{1,2}";
my $reIP=join('[.]', ($blocIP)x4 );
on peut aussi utiliser . à la place de [.] mais j'ai tendance à privilégier les solutions sans \ c'est toujours le bordel dans les imbrications :)
Il ne faut pas décorner les boeufs avant d'avoir semé le vent
[^] # Re: Ça manque de classes...
Posté par jyes . Évalué à 3.
Non : 266.277.288.299 n’est pas une IPv4 valide.
Pour tout ce qui contient des règles de sens autre que le texte brut, les regexp deviennent vite relou :-).
[^] # Re: Ça manque de classes...
Posté par kna . Évalué à 4.
Ben le problème avec les regexp, c'est qu'une fois qu'on les maitrise on en abuse.
Il faut simplement savoir quand les utiliser et quand ne pas les utiliser.
En l'occurence, pour vérifier si un nombre est inférieur à 255, il existe des meilleurs méthodes :)
[^] # Re: Ça manque de classes...
Posté par ganymede . Évalué à 3.
Je suis d'accord. Voici tout de même, pour ceux que ça intéresserait, une expression rationnelle qui valide correctement une IPv4 :
\b((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(.|$)){4}\b
[^] # Re: Ça manque de classes...
Posté par freem . Évalué à 2.
Si j'en crois wikipedia, même cette regex ne valide pas correctement toutes les formes d'IPv4:
Malheureusement il n'y a pas de pointeur vers une source plus fiable à côté de ce paragraphe, et j'ai la flemme d'en chercher un moi-même. En tout cas, le fonctionnement de ping sur ma Debian semble confirmer cette affirmation.
M'enfin, ça prouve bien que c'est juste une mauvaise idée que d'utiliser les regex quand on veut détecter une syntaxe, du coup. D'ailleurs, existe-t-il un outil raisonnablement utilisable en ligne de commande permettant de détecter un pattern syntaxique? (en espérant ne pas me planter sur le terme "syntaxique"… déjà ridiculisé une fois dans ce thread après tout :))
[^] # Re: Ça manque de classes...
Posté par anaseto . Évalué à 2.
Ça ne prouve rien du tout, ça dépend juste du type de syntaxe que l'on veut matcher, et si l'on veut juste répondre par oui ou non, ou bien expliquer pourquoi ça ne matche pas (auquel cas une expression régulière à elle toute seule ne suffira pas). Pour le cas des expressions régulières pour les ipv4 et traitant les différents cas, ça existe. Par contre l'expression régulière donnée dans le message juste avant n'est pas exacte (elle matche des trucs en plus qui ne sont pas des ips, en partie parce qu'elle traite le dernier groupe comme les premiers, ce qui permet de mettre un caractère à la fin).
[^] # Re: Ça manque de classes...
Posté par freem . Évalué à 2.
Pas con du tout ça!
[^] # Re: Ça manque de classes...
Posté par ɹǝıʌıʃO . Évalué à 8.
Heureusement que Benoît a précisé qu’il s’agit de classes de caractères. Sinon, on aurait pu croire qu’il s’agit de classes de caractères.
[^] # Re: Ça manque de classes...
Posté par freem . Évalué à 2.
Pas faux… du coup me moinsserais moi-même si je pouvais :s
[^] # Re: Ça manque de classes...
Posté par FantastIX . Évalué à 5.
Ça, je parie que Emacs le fait déjà.
[^] # Re: Ça manque de classes...
Posté par kna . Évalué à 2.
À l'origine, les classes n'avaient pas été faite pour simplifier ou donner une notation « human-readable » mais pour résoudre un problème : les intervalles ne donnent pas le même résultat en fonction de l'encodage utilisé. Par exemple la chaine
[A-Z]
peut donner[ABCD...XYZ]
dans un encodage et[AaBbCc...YyZ]
dans un autre.[:upper:]
donnera toujours[ABCDEF...XYZ]
.[^] # Re: Ça manque de classes...
Posté par Benoît Sibaud (site web personnel) . Évalué à 6.
Oui, mais ne pas oublier qu'il peut prendre en compte les majuscules accentuées (de même que [ABCDEF…XYZ]).
[^] # Re: Ça manque de classes...
Posté par fouinto . Évalué à 2.
C'est intéressant comme exemple !
Je suis régulièrement em…bêté par ce genre de chose.
Mon utilisation des expressions rationnelles est très basique : je m'en sert pour valider (match) le contenu de champs de formulaires sur des applications web php et/ou JS le plus souvent (pas taper !!!).
La plupart du temps, soit je les ai déjà dans mon arsenal (voir dans celui de PHP), soit je fouille un peu sur le net pour trouver mon bonheur.
Je cale toujours sur les champs libellé ("texte libre") : impossible de valider un texte accentué sans énumérer (d'une manière¹ ou d'une autre²) l'ensemble de caractères accentués…
¹ je met tous les caractères accentués dans mon expression rationnelle,
² je transforme ma chaîne pour remplacer tous les caractères accentués par les équivalents non-accentués avant de les passer dans un
^[:alpha:]$*
par exemple…Ma question est donc la suivante : ton exemple est-il propre à grep ?
[^] # Re: Ça manque de classes...
Posté par Benoît Sibaud (site web personnel) . Évalué à 5.
Etc.
[^] # Re: Ça manque de classes...
Posté par anaseto . Évalué à 2.
Comme les autres te l'ont fait remarqué, des classes de caractères ne servent pas à définir une classe de chaînes, mais une classe de caractères. Par contre, dans les langages qui permettent de combiner des regexps précompilées, on peut réutiliser des regexps exportées par un module (comme Regexp::Common). Après, pour des choses comme une adresse mail, un module avec une fonction qui le valide peut être suffisant si l'on a pas besoin de combiner ça avec une autre regexp. Et comme ça, pas besoin de savoir si c'est implémenté par une regex ou autre ; et d'ailleurs une simple regexp a ses limites pour donner un bon message d'erreur pour expliquer pourquoi l'adresse n'est pas valide (même si en Perl c'est faisable vu qu'on peut exécuter du code lorsque telle ou telle partie de la regexp a déjà matché).
[^] # Re: Ça manque de classes...
Posté par GCN (site web personnel) . Évalué à 4.
Valider proprement une adresse e-mail, c'est chaud.
Comme on peut le lire ici → http://www.bortzmeyer.org/arreter-d-interdire-des-adresses-legales.html mieux vaut laisser passer des adresses invalides qu'en interdire des valides ;).
.+@.+
ou.+?@.+
[^] # Re: Ça manque de classes...
Posté par barmic . Évalué à 4.
C'est pourtant pas si compliqué.
https://metacpan.org/source/RJBS/Email-Valid-1.198/lib/Email/Valid.pm#L386
…
Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)
# Place aux jeux!
Posté par tfeserver tfe (site web personnel) . Évalué à 4.
Pour ceux qui aprennent les regex, c'est toujours bien de le faire en jouant:
Voila quelques liens:
[^] # Re: Place aux jeux!
Posté par lecteur . Évalué à 1.
Dans le premier jeu ( http://regex.alf.nu/1 ), si on propose par exemple l'expression rationnelle :
a?+
on a le droit au message suivant :
(invalid regex)
ce qui signifie que la validité de l'expression rationnelle proposée est probablement déterminée par… une expression rationnelle.
https://xkcd.com/1313/
[^] # Re: Place aux jeux!
Posté par tfeserver tfe (site web personnel) . Évalué à 1.
/a?+/ c'est valide ça?
[^] # Re: Place aux jeux!
Posté par Moonz . Évalué à 4. Dernière modification le 10 février 2016 à 16:15.
Oui : http://www.regular-expressions.info/possessive.html
Pour faire court, c’est pour interdire au moteur d’expression régulière de faire du backtracking sur un choix précis. Ici, c’est le choix est : "a?" matche-t-il un caractère ou 0 ?
/^a?ab/
arrivera a matcher "ab", mais/^a?+ab/
n’y arrivera pas, parce que dans le second cas "a?" a pris la décision de consommer le premier "a", et il ne reviendra pas sur cette décision ("+"), même quand cette décision implique un échec de la reconnaissance globale.# Outil graphique
Posté par LupusMic (site web personnel, Mastodon) . Évalué à 3.
Il y a quelques années je m'étais amusé à écrire une application Gtk permettant de tester une regex. C'est encore toujours un embryon, je l'ai juste mis à jour pour compiler avec de nouvelles moutures de Boost. Pull requests bienvenues : https://github.com/LupusMichaelis/warg
[^] # Re: Outil graphique
Posté par toctoc1 . Évalué à 3.
Comme celui-ci : http://regexper.com/#\d{2%2C6}
[^] # Re: Outil graphique
Posté par LupusMic (site web personnel, Mastodon) . Évalué à -2.
Je hais les application web.
[^] # Re: Outil graphique
Posté par Guillaume Denry (site web personnel) . Évalué à 9.
Je déteste les épinards en boîte.
[^] # Re: Outil graphique
Posté par LupusMic (site web personnel, Mastodon) . Évalué à 2.
C'est vrai que c'est meilleur frais, les épinards.
En fait, j'ai un énorme avec cette tendance à mettre tout en web. C'est lent, ça n'est pas ergonomique, ça pose des problèmes de sécurité, ce n'est pas utilisable hors ligne, etc.
[^] # Re: Outil graphique
Posté par Guillaume Denry (site web personnel) . Évalué à 3.
Je tomberai pas dedans, j'ai pas le temps, y'a potentiellement des kilomètres de discussion derrière, pour chacun des points que tu reproches aux appli web.
# arf tu oublies le modificateur ? pour les * ? +
Posté par fearan . Évalué à 7. Dernière modification le 09 février 2016 à 13:38.
hé oui depuis quelques temps on peut ajouter ? à '*', '+', '?' pour les transformer les quantificateur en non-glouton.
Par défaut
a*(.*)b*
suraaaaaaaaaacbbbbbbbbbbb
va capturer
cbbbbbbbbbbb
dans les ()si on fait
a*?(.*)b*
la totalité de la chaine sera prise dans les ()
si on fait
a*?(.*?)b*
on aura capturé
aaaaaaaaaac
Autant dire que pour du parsing simple (sans prise en compte des caractère d'échappement), on peut isoler les chaines de caractères par du
"(.*?)"
au lieu d'écrire"[^\"]*"
Il ne faut pas décorner les boeufs avant d'avoir semé le vent
[^] # Re: arf tu oublies le modificateur ? pour les * ? +
Posté par anaseto . Évalué à 6. Dernière modification le 08 février 2016 à 19:44.
Il y a aussi le modificateur
+
qui permet d'interdire le backtracking, et du coupaaa
ne matche pas l'expression régulièrea++a
, car lea++
prend tous lesa
.(en Perl en tous cas, parce que ces modificateurs n'existent pas dans toutes les implémentations des regexps, ni le
?
, d'ailleurs).[^] # Re: arf tu oublies le modificateur ? pour les * ? +
Posté par fearan . Évalué à 2. Dernière modification le 09 février 2016 à 13:37.
arf me suis pas relu les remplacer les
(.)
par(.*)
et(.?)
par(.*?)
Il ne faut pas décorner les boeufs avant d'avoir semé le vent
[^] # Re: arf tu oublies le modificateur ? pour les * ? +
Posté par anaseto . Évalué à 3.
Une étoile plutôt
(.*)
.[^] # Re: arf tu oublies le modificateur ? pour les * ? +
Posté par fearan . Évalué à 2.
rahhh c'est la mise en forme le texte était bon lui…
Il ne faut pas décorner les boeufs avant d'avoir semé le vent
[^] # Re: arf tu oublies le modificateur ? pour les * ? +
Posté par Benoît Sibaud (site web personnel) . Évalué à 3.
Corrigé, merci.
# echo "topinambour: légume oublié" | sed -r 's/.+(:.+)/man page\1/'
Posté par machin_là . Évalué à 10.
Bonsoir
Il serait bien de rappeler tout le monde que les man/info pages sont les références qu'il faut privilégier
par exemple , pour sed : "info sed" a une section sur les regex qu'il supporte
Pour PCRE (Perl-compatible regular expression) utilisées par perl,python,ruby,java … après avoir installer "pcre-devel" on dispose de "man pcre" et surtout de "man pcrepattern"
Pour les tests , le "man pcre" nous indique que l'outil pcretest existe
Pensez à la planète, économisez de la BP: installer les man pages sur vos postes, et n'utilisez le web que quand c'est nécessaire :-)
[^] # Re: echo "topinambour: légume oublié" | sed -r 's/.+(:.+)/man page\1/'
Posté par aeten . Évalué à -1.
Tout à fait. Sous Debian, il s'agit du paquet libpcre3-dev.
[^] # Re: echo "topinambour: légume oublié" | sed -r 's/.+(:.+)/man page\1/'
Posté par barmic . Évalué à 3.
Non, perl n'utilise pas PCRE à ma connaissance. PCRE est une bibliothèque créée pour reproduire les extensions Perl et les rendre disponibles d'autres langages et comme c'est pas rigolo de juste ré-implémenter, ils ont ajouter propre trucs. C'est du moins ce que je comprends de l'introduction de cet article http://articles.mongueurs.net/magazines/linuxmag106.html (et ça me semble coller avec le Perl-compatible et pas juste PRE pour Perl regular expression).
Tous les contenus que j'écris ici sont sous licence CC0 (j'abandonne autant que possible mes droits d'auteur sur mes écrits)
# Question bête
Posté par chimrod (site web personnel) . Évalué à 2.
Existe-t-il une regex permettant de valider une regex ?
De manière plus générale, est-ce qu'il est possible de savoir si une grammaire X peut être validée par regex ? (Je suppose qu'il doit y avoir un champs de recherche qui s'intéresse à ce genre de question ?)
[^] # Re: Question bête
Posté par Dr BG . Évalué à 3.
Oui, il faut que la grammaire soit rationnelle.
[^] # Re: Question bête
Posté par anaseto . Évalué à 10.
Si on se limite aux expressions rationnelles au sens strict, non : par exemple le simple fait de pouvoir utiliser des parenthèses pour faire des groupes demande de savoir reconnaître si une expression est bien parenthésée, ce qu'une expression rationnelle ne peut pas faire. Pour ça il faut un automate à pile, car les expressions bien parenthésées ont une grammaire algébrique, mais pas rationnelle (en gros, il faut pouvoir compter, ce qu'une expression régulière ne sait pas faire).
En pratique les « regex » (qui n'en sont pas vraiment), permettent de faire ce genre de choses grâce aux diverses extensions. Les expressions régulières Perl permettent théoriquement de faire quoi que ce soit étant donné que l'on peut exécuter conditionnellement du code quelconque si une partie de regex a matché. D'autres (comme PCRE) permettent au moins de faire des appels récursifs à des groupes, ce qui permet par exemple de décrire les expressions bien parenthésées, les palindromes, etc.
[^] # Re: Question bête
Posté par chimrod (site web personnel) . Évalué à 2.
Merci beaucoup pour le détail de la réponse.
# ack, Unicode
Posté par cognominal . Évalué à 4. Dernière modification le 13 février 2016 à 10:17.
Je suis étonné de voir que ce post ne mentionne ni ack, ni Unicode et pas le futur que sont les grammaires Perl 6. Excellent article, mais Il aurait pu être écrit il y a vingt ans.
ack
ack est un outil permet de chercher toute une arborescence évitant de jongler avec find et xargs. Il est intégré dans emacs et probablement dans vim.
grammaires Perl 6
Les systèmes dit d'expressions régulières ne sont pas modulaires et donc ne peuvent pas traiter les cas complexes.
Perl 6 utilise un système de grammaires qui sont une forme de classe, les règles y sont des méthodes qui s'appelle les unes les autres. Notionnellement, tout au moins, puisque les grammaires sont un composite de NFA, d'analyse récursive et d'analyse d'expressions (aussi récursive mais à base de piles opérandes et opérateurs) avec des opérateurs.
Perl 6 et Unicode : forme normalisée NFC
Faire sérieusement de l'analyse syntaxique avec Unicode est difficile sauf avec Perl 6. Un des problèmes résolu par Perl 6 est que des graphèmes peuvent être composés de plusieurs codepoints. Avec les formes de normalisations actuelles, cela
signifie que des opérations en O(1) ne le sont plus puisqu'on ne peut pas prévoir l'offset d'un graphème.
Perl 6 propose la normalisation NFC avec des graphèmes synthétiques. Elle ne sort pas de l'interpréteur Perl 6 donc Perl 6 est par ailleurs conforme à la norme Unicode.
La liste des fonctionnalités spécifique à Perl 6 serait trop longue pour ce post.
Un seul exemple, donc.
En Perl 6, des tâches comme mettre en majuscule une "lettre accentuée" est triviale.
Mieux que les DSL, Perl 6 et les slangs
Finalement, Perl 6 est écrit en Perl 6 donc est analysé en Perl 6. Il permet l'usage de slangs (argot en anglais, mais aussi sub*lang*age, c'est à dire de tisser finement syntaxiquement un langage dans un autre. On parle beaucoup de DSL mais ça, c'est beaucoup mieuxmême si pour le moment, certains détails laissent à désirer pour les perfectionnistes que sont les perlers.
Ainsi Perl6 comprend, le langage de quotes avec un contrôle très fin de ce qui est expansé et de ce qui ne l'est pas.
et deux langages de regex (le mot pour ne pas le terme expression rationnelles beaucou trop limitatif), celui de Perl 5 et celui de Perl 6. Oui, il y a plusieurs manières d'utiliser Perl 5 dans Perl6 !
Les grammaires Perl 6 sont le futur
Je peux dire avec confiance que quelque soit le succès ou l'insuccès de Perl 6, les grammaires Perl 6 influenceront beaucoup de languages comme les expressions rationnelles de Perl 1/2/3/4/5 l'ont fait depuis près de trente ans.
La doc et les tutoriels
La doc http://docs.perl6.org/ n'est pas complète, mais il faut déjà un bon niveau pour repérer les manques.
La communauté Perl 6 francophone bien que non organisée est à la pointe pour les tutoriels, même si seul ceux de Laurent Rosenfeld ont pour original le français.
Naoum Hankache est l'auteur de Perl 6 intro : http://perl6intro.com/
Vendethiel celui de Perl 6 in y minutes: https://learnxinyminutes.com/docs/perl6/
Laurent Rosenfeld a pondu tout une série d'excellent tutorilels: http://laurent-rosenfeld.developpez.com/tutoriels/perl/perl6/les-bases/
[^] # Re: ack, Unicode
Posté par cognominal . Évalué à 1.
J'ai oublie de dire que ack est un outil Perl 5 et de donner un URL
http://beyondgrep.com/
[^] # Re: ack, Unicode
Posté par El Titi . Évalué à 4.
Merci !
J'avais presque oublié ce langage et en relisant ton post, auquel je n'ai presque rien compris …mais qui m'inspire un total respect, je me suis souvenu:
http://www.fastcompany.com/3026446/the-fall-of-perl-the-webs-most-promising-language
[^] # Re: ack, Unicode
Posté par Aluminium95 . Évalué à 1.
Je suis curieux, quelle différence fais-tu entre « regular expression (regex) » et « expression rationnelle » ? En effet il y a une équivalence entre langage rationnel et régulier. Donc c'est peut-être que « regex » fait implicitement référence à des expression étendues ?
Il faut quand même faire attention, parce qu'une grammaire n'est pas une expression régulière. Le pouvoir expressif d'une expression rationnelle est plus faible, mais en contre partie tout est plus facile : stabilité des langages par intersection, union, complémentaire, morphismes, algorithmes (très) efficaces pour les traiter etc… Donc quand une expression suffit, il ne sert à rien d'aller chercher une grammaire.
[^] # Re: ack, Unicode
Posté par cognominal . Évalué à 1. Dernière modification le 13 février 2016 à 10:18.
La réponse est le premier paragraphe de https://design.perl6.org/S05.html.
En gros, en Perl 6, une regex est un terme qui englobe celui d'une expression régulière.
Selon les choix de défaut pour le backtracking et de traitement des espaces, un utilisera le mot règle, token ou regex (cette fois-ci dans un sens précis).
Quand je parle de NFA comme un des trois sous-moteurs, c'est justement ce qui implémente
la partie expression régulière. C'est d'ailleurs pour ça que je parle dans ce cas d'appel "notionnel" des méthodes d'une grammaire. Dans le cas des NFA, c'est une convention syntaxique qui recouvre autre chose qu'un bête appel. C'est pour ça que Larry Wall insiste sur le fait qu'on a un mix de procédural (les expressions avec opérateurs, et le récursif descendant) et de déclaratif (implémenté par les NFA).
D'ailleurs, techniquement, le moteur d'expression avec opérateurs est implémenté en terme du moteur récursif descendant dont il n'apparait pas dans la documentation. Dommage car il est essentiel pour ceux qui veulent utiliser rakudo/nqp comme base pour implémenter d'autres langage que Perl.
Bien sûr, Perl 6 n'impose pas d'utiliser une grammaire quand cela n'est pas nécessaire pas plus qu'il n'impose de déclarer explicitement une classe et une fonction pour afficher "Hello word".
C'est la spécificité de Perl, de proposer des raccourcis syntaxiques pour les cas les plus fréquents.
Le raccourci allant jusqu'à l'absence syntaxique de l'entité conceptuelle sous-jacente (ou du pattern selon la terminologie de "design patterns").
Exemple: on itère très souvent en Perl 6 mais il n'y a guère que les implémenteurs de Perl 6 qui manipulent explicitement des opérateurs.
Là est le manque criant de "design patterns", une partie du design d'un pattern se doit d'être syntaxique.
Evidemment ce n'est pas possible avec des langages rigides comme C++ donc ça ne leur est même pas venu à l'idée.
C'est une nouvelle frontière explorée depuis 30 ans par Perl et soigneusement ignorée par ailleurs. Les concepteurs d'un langage vont choisir leur syntaxe dans la famille dérivée d'algol (C, Java… ) où celle dérivée de ISWIM (haskell, elm, idris…) sans trop se poser de questions.
C'est un souci en moins et ça permet un apprentissage plus facile. Mais ça fige l'état de l'art.
C'est le propre d'un langage que d'incarner les patterns les plus communs. Avec les slangs, Perl 6 permet de ce faire et cela va plus loin que la notion de DSL qui m'a toujours semblé bien vague.
Jonathan Worthington, un des implémenteurs de rakudo un (à vrai dire le) compilateur Perl 6 a une belle remarque qui distille l'essence même de Perl comparé à d'autres langages. je vais paraphraser faute de retrouver l'original.
On reproche à Perl d'être illisible car il faut du temps pour maîtriser sa syntaxe mais c'est justement ça qui permet à un programme Perl d'être compréhensible au programmeur entraîné.
Les regex et les grammaires en sont un exemple. Un programme C qui parse "à la mano" une chaîne de caractères est très lisible pour le programmeur qui ne connait pas les regex mais le résultat est moins compréhensible qu'une regex et un réceptacle de bug potentiels dû à la manipulation explicite de pointeurs.
Pour paraphraser une expression anglopone : Perl est un goût acquis.
[^] # Re: ack, Unicode
Posté par Moonz . Évalué à 4.
De très très loin, ça ressemble pourtant très fort à la métaprogrammation de F#, et aux macros de Rust, Nim et Scala, non ?
[^] # Re: ack, Unicode
Posté par cognominal . Évalué à 1.
Oui. Je ne connaissais pas Nim. Merci pour le pointeur.
# fichier french
Posté par refreketu . Évalué à 1.
Où se trouve ce fichier ?
[^] # Re: fichier french
Posté par Benoît Sibaud (site web personnel) . Évalué à 6.
Paquet wfrench qui amène le fichier /usr/share/dict/french
[^] # Re: fichier french
Posté par refreketu . Évalué à 1.
Merci !
Suivre le flux des commentaires
Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.