Regexes

Exercices

  1. Écrire une regex pour matcher les dates 17/12/1984.

    ([1-9]|[1-2][0-9]|3(0|1))/([1-9]|1[0-2])/[1-9][0-9]*

    Explication :

    • avant le 1er slash, soit un chiffre entre 1 et 9, soit un nombre entre 10 et 29 (1 ou 2 puis 0 ou 1 ou … ou 9), soit 30 ou 31
    • entre les 2 slashes, soit un chiffre entre 1 et 9, soit un nombre entre 10 et 12 (1 puis 0 ou 1 ou 2)
    • après le 2e slash, un chiffre différent de 0 puis autant de chiffres qu’on veut.
  2. Écrire une regex pour matcher les adresses IPv4.

    ([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\. .... \.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])

    Le même motif 4 fois, séparé par des . (qu’il faut protéger sinon, c’est la regexp “.” qui capture n’importe quel caractère).

    Ce motif signifie :

    • un chiffre entre 0 et 9
    • ou un nombre entre 10 et 99
    • ou un nombre entre 100 et 299
    • ou un nombre entre 200 et 249
    • ou un nombre entre 250 et 255

    Pour la suite, on notera cette regexp RegexpIPExo2.

  3. Écrire une regex pour matcher les adresses mails.

    [a-zA-Z]([a-zA-Z0-9]|\.|-)*@[a-zA-Z]([a-zA-Z0-9]|\.|-)*\.[a-zA-Z][a-zA-Z]*

    Avant l’@, on a une lettre puis autant de caractères acceptables qu’on veut. Après l’@, on a la même chose plus un point et des lettres (au moins une).

    Pour la suite, on notera RegexpNDExo3 la partie après l’@ (partie qui matche les noms de domaine).

  4. Écrire une regex pour matcher les URLs.

    http(s|)://(RegexpNDExo3 | RegexpIPExo2)(:[1-9][0-9]*|)(/([a-zA-Z0-9]|-|\.)*)*

  5. Écrire une regex qui matche les md5 (nombres hexa à 32 chiffres).

    On notera e{17} pour signifier 17 répétition de la regexp e (ou e^{17}).

    [0-9a-f]{32}|[0-9A-F]{32}

  6. Étant données des lignes de log au format suivant : Sep 7 08:45:14 whirlwind sshd[28333]: Invalid user admin from 122.225.109.108

    1. Écrire une regex qui ne donne que les lignes pour le 9 septembre.

      Sep *9.* (il peut y avoir 1 ou 2 espaces, je mets * qui permet d’en avoir 1, 2, 3, …

    2. Écrire une regex qui ne donne que les lignes pour le 9 septembre entre 9h30 et 10h.

      Sep *9 09:[3-5].*

    3. Écrire une regex qui ne donne que les lignes pour le 9 septembre entre 9h30 et 10h concernant sshd.

      Sep *9 09:[3-5].*sshd.*

  7. Proposer une regex qui, dans un fichier html, matche les blocs div (d’une balise div ouvrante à la balise fermante correspondante).

    C’est impossible à réaliser par une regexp ! Il faudrait pouvoir compter.

À retenir

  • [1-9][0-9]* capture tous les entiers à partir de 1
  • .* capture toutes les chaînes de caractères envisageables
  • [A-Za-z][A-Za-z]* tous les mots composés de majuscules et minuscules d’au moins une lettre
  • (s|) s ou rien

Syntaxe en plus

  • Accolades : e{3} représente la répétition 3 fois de e (en d’autres termes eee)
  • Plus : e+ représente la répétition au moins 1 fois (e+ est équivalent à ee*)
  • Point d’interrogation : e? représente l’option, ce qui équivaut à la répétition au plus 1 fois (e? est équivalent à (e|))

Pipes et filtres

Les commandes suivantes pourront êter utilisées comme filtres : grep (trouver des motifs), tr (remplacer des caractères), sed (remplacer des motifs), head (sélectionner les premières lignes), tail (sélectionner les dernières lignes), uniq (supprimer les doublons), wc (compter les lignes, mots et caractères), sort (trier), cut (couper des colonnes), comm (lignes en commun entre deux fichiers), join (jointure). On pourra se référer à leur manuel pour plus d’informations.

  1. Écrire une commande qui dans le fichier /var/log/auth.log extrait parmi les lignes pour le 10 septembre entre 9h30 et 10h00 concernant sshd, les IPs qui apparaissent.

    cat /var/log/auth.log | grep 'Sep 10 09:[3-5].*sshd.*' | grep -o '[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*' | sort | uniq

  2. Écrire une commande qui affiche les lignes du fichier /var/log/auth.log en remplaçant les IPs par XXX.XXX.XXX.XXX dans les lignes pour le 10 septembre entre 9h30 et 10h00 concernant sshd.

    cat /var/log/auth.log | grep 'Sep 10 09:[3-5].*sshd.*' | sed 's/[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*/XXX.XXX.XXX.XXX/g'

/usr/share/dict/words contient une liste de mots que connaît le système (pour faire des vérifications orthographiques) sous la forme d’un mot par ligne.

  1. Écrire une commande pour afficher le nombre de mots dans ce fichier.

    wc < /usr/share/dict/words

  2. Ligne de commande pour afficher les mots de ce fichier contenant truc.

    grep truc < /usr/share/dict/words

  3. Ligne de commande pour afficher les mots contenant truc de plus de 8 lettres.

    grep truc < /usr/share/dict/words | grep '.........'

  4. Ligne de commande pour faire dire par un pingouin le dernier mot de plus de 8 lettres contenant truc dans l’ordre alphabétique.

    grep truc < /usr/share/dict/words | grep '.........' | tail -n 1 | cowsay -f tux

  5. Étant donné un fichier livre.txt contenant un texte (avec des signes de ponctuations, des passages à la ligne, des majuscules). Proposer une ligne de commande donnant les 10 mots les plus utilisés. À défaut, un script donnant les 10 mots les plus utilisés…

    cat livre.txt | sed 's/ /\n/g' | tr -d ' ,.:;-?!()' | tr '[[:upper:]]' '[[:lower:]]' | grep -v '^ *$' | sort | uniq -c | sort -n | tail