Cours n° 8, 21 novembre 2013

Jean-François Perrot

Expressions régulières en Perl - 1

  1. Contextes de mise en œuvre des expressions régulières
    1. Généralité
    2. Variété

  2. Utilisation des e.r. en Perl
    1. Les e.r. apparaissent en Perl dans trois contextes
    2. Le caractère séparateur

  3. Exemples
    1. Couper sur les blancs et les tabulations
    2. Les nombres (v.1)
    3. Les commentaires à la C (v. 1)
    4. Ajoutons-y les commentaires en fin de ligne


Contextes de mise en œuvre des expressions régulières

  1. Généralité

    Les e.r. sont utilisées à peu près dans toutes les situations où interviennent des textes, à commencer par la programmation en shell.
    Pendant longtemps, malheureusement, dans chacune de ces situations, la syntaxe utilisée pour les e.r. variait légèrement, mais suffisamment pour faire de leur utilisation un redoutable casse-tête.
    La situation s'est améliorée aujourd'hui, la syntaxe proposée par Perl étant assez généralement adoptée.

    En shell : grep et sed
    grep expreg fichier -> imprime les lignes du fichier qui contiennent expreg
    sed expreg edition fichier -> effectue la commande edition sur les lignes du fichier qui contiennent expreg
  2. Variété

    Suivant les langages de programmation, les e.r. peuvent prendre des statuts différents :
    Cette interrogation sur l'essence des e.r. dans un langage donné est en fait d'un intérêt secondaire.
    L'essentiel est de connaître le contexte dans lequel elles apparaissent, c'est-à-dire leur mode d'emploi.

    Or, même si tous les langages proposent grosso modo les mêmes fonctionnalités,
    les détails de syntaxe pour obtenir ces fonctionnalités varient fortement.
    On n'utilise pas les e.r. (même si elles s'écrivent grosso modo de façon identique) par les mêmes procédés
    Nous nous limiterons ici au cas de Perl.

Utilisation des e.r. en Perl

Exemples

  1. Couper sur les blancs et les tabulations

    pour interpréter un texte sur deux colonnes comme un tableau associatif (hash) :
    Luc         12
    Maurice     18
    Juliette    07

    <-----------> my %tab;
    $tab{'Luc'} = 12
    $tab{'Maurice'} = 18
    $tab{'Juliette'} = 07


    open(ENTREE, "<$fich");

    my %tab;
    my @tablignes = <ENTREE>;
    foreach my $ligne ( @tablignes ){
        chomp($ligne); # supprime le "\n" final
        my ($le_nom, $la_note) = split( /[ \t]+/, $ligne);
        $tab{$le_nom} = $la_note;
    }
    return %tab;


    fichier TxtVersTab.pl, avec un fichier-exemple pour essais NomsNotes.txt.

    Fonctionnement (en ligne de commande) :
    jfp% perl TxtVersTab.pl NomsNotes.txt
    Elsa09Franck12Maurice18Kevin09Elisabeth07Joseph09Josette19Max07Aline12Antoinette12Julien13Alexandre09Ernestine18Mauricette12Jules11Francine13Pierre08Hélène13Jean-Pierre09Juliette07Christine12Paulette09Jacques09Luc12


    Cette sortie est obtenue en demandant "print %tab", elle donne les noms-notes dans un ordre arbitraire, rassemblés en une seule chaîne.
    Voici une version plus perfectionnée, avec une impression dans le même ordre, mais ligne à ligne : fichier TxtVersTabP.pl.
  2. Les nombres (v.1)

    Avec l'expression censée représenter les nombres écrits en décimal, en octal et en hexadécimal (sur son élaboration, voyez ici):
    [1-9][0-9]*|0([0-7]+|x[0-9A-F]+)
    extraire d'un texte toutes les sous-chaînes maximales représentant des nombres ? Pas tout de suite...
    Commençons par extraire toutes les lignes contenant des nombres :


    sub extrnb1($){ #arg. nom de fichier
        my ($fich) = @_;
        open(ENTREE, "<$fich");

        my $er = '[1-9][0-9]*|0([0-7]+|x[0-9A-F]+)';
        my @tablignes = <ENTREE>;
        my @tabnb = grep(/$er/, @tablignes);
        foreach my $lgn ( @tabnb ){
           print $lgn; #le saut de ligne est resté en place !
        }
    }#extrnb


    fichier extrnb1.pl, donnée pour essais nb.txt.

    Variante : trouver dans un texte HTML ou XML les lignes contenant des entités-caractères, comme &#248; ou &#x2029A;
    désignant des caractères Unicode par leur numéro en décimal ou en hexadécimal.
    my $er = '&#([1-9][0-9]*|x[0-9A-F]+);';
    etc.
  3. Les commentaires à la C (v. 1)

    que nous avons déjà vus : /[*]([^/*]|[/]|[*]+[^/*])*[*]+/

    Renvoyer un texte en supprimant tous les commentaires... ???
    commençons par supprimer le premier !

    sub supprCommC($){ #arg. nom de fichier
        my ($fich) = @_;
        open(ENTREE, "<$fich");

        my $erc = '/[*]([^/*]|[/]|[*]+[^/*])*[*]+/'; #sans '\'
        my @tablignes = <ENTREE>;
        my $txt = join('', @tablignes); # regroupe toutes les lignes en une seule chaîne
        $txt =~ s=$erc= =; # avec '=' comme séparateur pour ne pas avoir à marquer les '/' par '\'
        print $txt;

    }#supprCommC



    fichier supprCommC.pl, donnée pour essais exCom.txt.
    Regardez bien le résultat...

    Si vous voulez supprimer tous les commentaires, il faut ajouter le suffixe g (comme global) à la fin de la substitution :
    $txt =~ s=$erc= =g;
  4. Ajoutons-y les commentaires en fin de ligne

    que nous avons aussi vus : //[^\n]*\n
    même question...

    sub supprToutComm($){ #arg. nom de fichier
        my ($fich) = @_;
        open(ENTREE, "<$fich");

        my $erc = '/[*]([^/*]|[/]|[*]+[^/*])*[*]+/'; # la même
        my $erfl = '//[^\n]*\n'; # idem
        my $er = "$erc|$erfl"; # disjonction ou réunion...

        my @tablignes = <ENTREE>;
        my $txt = join('', @tablignes);
        $txt =~ s=$er= =; # avec '=' comme séparateur
        print $txt;
    }#supprToutComm



    fichier supprCommCFL.pl, donnée supplémentaire pour essais exCom2.txt.

Suite au prochain cours....