La BAO3 consiste en l'extraction de patrons morpho-syntaxiques à partir des fichiers étiquetés en BAO2

Nous avons procédé de trois manières différentes :

1° La manière rustique

Fiche technique du script :
TRAITEMENT DE L'ETIQUETAGE DE CORDIAL
Premier argument du programme : le fichier cordial
Deuxième argument du programme : le fichier patron
SORTIE : fichiers textes comprenant les patrons extraits

#!/usr/bin/env perl
# perl -c 
# creation d'un fichier de sortie
print "Bonjour ! Veuillez choisir un nom de fichier pour contenir patrons extraits :\n";
my $fic=;
open(FIC1, ">$fic");
# creation des listes pour le contenu 
my @LISTETOKEN;
my @LISTELEMME;
my @LISTEETIQUETTE;
#--------------------------------------------------
# lecture du fichier PATRON 
# 2e arg : fichier motif, on lit le fichier 
open(PATRON, "$ARGV[1]"); 
# a chaque condition de la liste on met le contenu dans une position de la liste : lecture globale du fichier au lieu de ligne a ligne 
my @LISTEPATRON=;
close (PATRON);
# 1er arg : fichier cordial 
open (CORDIAL, "$ARGV[0]");
# on lit chaque ligne et on s'arrete au ponctuation
# lecture du fichier ligne a ligne 
while(my $ligne=){
  # avant de traiter la ligne, on enleve les retours a la ligne 
  $ligne=~s/\r//;
  chomp($ligne);
  # debut de ligne tout sauf une tabulation 
  # format des lignes qui nous interessent : 
  # ^[^\t]+\t[^\t]+\t[^\t]+$
  # on met des parentheses pour capturer les ensembles dans $1 $2 $3 que l'on mettra dans des listes
  if ($ligne =~/^([^\t]+)\t([^\t]+)\t([^\t]+)$/) {
    # creation des variables
    # my ($token, $lemme, $etiquette) = ($1, $2, $3);
    my $token = $1;
    my $lemme = $2;
    my $etiquette = $3;
    #print $ligne;
    # si l'etiquete ne contient pas de ponctuation forte 
    if ($etiquette!~/^PCTF/){
      # on enregistre les contenus dans les listes correspondantes
      # push : rajoute des elements a la fin d'une liste 
      push(@LISTETOKEN, $token);
      push(@LISTELEMME, $lemme);
      push(@LISTEETIQUETTE, $etiquette);
    }
    # si on tombe sur des ponctuations on compare avec le fichier motif 
    else {
      # on transforme les listes en scalaire (pointeur vers une liste) : creation d'une reference 
      &compare(\@LISTETOKEN,\@LISTEETIQUETTE);
      # on purge les listes  
      @LISTEETIQUETTE=();
      @LISTETOKEN=();
      @LISTELEMME=();
    }
  }
}
# --------------------------
# comparaison des listes avec les lignes de motifs 
# il faudra transformer la liste d'etiquette en scalaire 
sub compare {
  # on dereference les scalaires pour qu'elles redeviennent des listes 
  my ($first, $second)=@_;
  my @LISTETOKEN=@$first;
  my @LISTEETIQUETTE=@$second;
  #print "Liste des token : @LISTETOKEN\n";
  #print "Liste des etiquettes des token: @LISTEETIQUETTE \n";
  #print "------------------------------------------\n";
  # pour chaque patron dans la liste LISTEPATRON
  foreach my $patron (@LISTEPATRON) {
    $patron=~s/\r//;
    chomp $patron;
    #print "Patron en cours : $patron \n";
    #print "------------------------------------------\n";
    # chercher dans la liste des etiquettes si on trouve $patron 
    # transformation d'une liste en scalaire 
    my $texte_des_etiquettes=join(" ",@LISTEETIQUETTE);
    # tant que le scalaire des etiquettes contient $patron : 
    while ($texte_des_etiquettes=~/$patron/g) {
      # on veut savoir combien il y a de blancs dans le contexte fauche de la zone de correspondance
      my $contextebefore=$` ;
      # print "CB: ",$contextebefore,"\n";
      my $compteurblanc=0;
      while ($contextebefore=~/\t/g) {
        $compteurblanc++;
      }
    my @MONPATRONENCOURS=split(/ /, $patron);
    # obtenir la valeur 
    my $longueurpatron=$#MONPATRONENCOURS;
    my $bornsup=$compteurblanc + $longueurpatron;
    # .. "jusqu'à"
    print "@LISTETOKEN[$compteurblanc..$bornsup]\n";
    print FIC1 "@LISTETOKEN[$compteurblanc..$bornsup]\n";
    print "------------------------------------------\n";
    # my $rep=;
    }
  }
}

Télécharger les fichiers obtenus


2° Extraction de patrons avec des requêtes XPATH

Fiche technique du script :
TRAITEMENT DE LA SURFACE

Lancement du programme depuis le terminal (MACOSX):
/usr/local/ActivePerl-5.16/bin/perl ScriptRH.pl 3208.xml patrons.txt

ENTREE : fichiers xml étiquetés en BAO2
SORTIE : fichiers txt comprenant les patrons extraits

#/usr/bin/perl
<new(XML_LIBXML_RECOVER => 2);
$xp->recover_silently(1);

# enregistrement du fichier XML dans la RAM : pb de saturation de la mémoire
my $dom    = $xp->load_xml( location => $tag_file );
# recupération élément racine: partir directement de l'article peut etre plus économique et faire une boucle 
my $root   = $dom->getDocumentElement();

# contruction de l'objet XPATH contexte, instancié à partir de l'élément root. 
# ouverture du fichier qui contient les motifs 
# pour chaque ligne il me faut faire ma recherche de forme 
my $xpc    = XML::LibXML::XPathContext->new($root);

# Ouverture du fichiers de motifs
open(PATTERNSFILE, $patterns_file) or die "can't open $patterns_file: $!\n";

# Boucle pour lire les lignes des motifs lecture du fichier contenant les motifs, un motif par ligne (par exemple : NOM ADJ)
while (my $ligne = ) {
  # Appel à  la procédure d'extraction des motifs
  &extract_pattern($ligne);
}

# Fermeture du fichiers de motifs
close(PATTERNSFILE);

# routine de construction des chemins XPath
sub construit_XPath{
  # On récupère la ligne du motif recherché
  my $local_ligne=shift @_;
  
  # initialisation du chemin XPath
  my $search_path="";
  
  # on supprime avec la fonction chomp un éventuel retour à la ligne
  chomp($local_ligne);
  
  # on élimine un éveltuel retour chariot hérité de windows
  $local_ligne=~ s/\r$//;
  
  # Construction au moyen de la fonction split d'un tableau dont chaque élément a pour valeur un élément du motif recherché
  my @tokens=split(/\s+/,$local_ligne);
  
  # On commence ici la construction du chemin XPath
  # Ce chemin correspond au premier noeud "element" de l'arbre XML qui répond au motif cherché 
  $search_path="//element[contains(data[\@type=\"type\"],\"$tokens[0]\")]";
  
  # Initialisation du compteur pour la boucle de construction du chemin XPath
  # gestion de la variabilité du nombre d'éléments par ligne dans le fichier motif
  my $i=1;
  while ($i < $#tokens) {
    # concaténation de following sibling
    $search_path.="[following-sibling::element[1][contains(data[\@type=\"type\"],\"$tokens[$i]\")]";
    $i++;
  }

  my $search_path_suffix="]";
  
  # on utilise l'opérateur x qui permet de répéter la chaine de caractère à sa gauche autant de fois que l'entier à sa droite,
  # soit $i fois $search_path_suffix
  $search_path_suffix=$search_path_suffix x $i;
  
  # le chemin XPath final
  # .= concaténation 
  $search_path.="[following-sibling::element[1][contains(data[\@type=\"type\"],\"".$tokens[$#tokens]."\")]"
                .$search_path_suffix;
    # print  "$search_path\n";

  # on renvoie à la procédure appelante le chemin XPath et le tableau des éléments du motif
  return ($search_path,@tokens);
}

# routine d'extraction du motif
sub extract_pattern{
  # On récupère la ligne du motif recherché
  #@_ = @ARGV dans une fonction
  my $ext_pat_ligne= shift @_;

  # Appel de la fonction construit_XPath pour le motif lu à la ligne courrante du fichier de motif
  my ($search_path,@tokens) = &construit_XPath($ext_pat_ligne);
  
  # définition du nom du fichier de résultats pour le motif en utilisant la fonction join
  my $match_file = "res_extract-".join('_', @tokens).".txt";

  # Ouverture du fichiers de résultats encodé en UTF-8
  open(MATCHFILE,">:encoding(UTF-8)", "$match_file") or die "can't open $match_file: $!\n";
  
  # création de l'objet XML::XPath pour explorer le fichier de sortie tree-tagger XML
  
  # Parcours des noeuds du ficher XML correspondant au motif, au moyen de la méthode findnodes
  # qui prend pour argument le chemin XPath construit précédement
  # avec la fonction "construit_XPath"
  my @nodes=$root->findnodes($search_path);
  foreach my $noeud ( @nodes) {
    # Initialisation du chemin XPath relatif du noeud "data" contenant
    # la forme correspondant au premier élément du motif
    # Ce chemin est relatif au premier noeud "element" du bloc retourné
    # et pointe sur le troisième noeud "data" fils du noeud "element"
    # en l'identifiant par la valeur "string" de son attribut "type"
    my $form_xpath="";
    $form_xpath="./data[\@type=\"string\"]";
    
    # Initialisation du compteur pour la boucle d'éxtraction des formes correspondants
    # aux éléments suivants du motif
    my $following=0;

    # Recherche du noeud data contenant la forme correspondant au premier élément du motif    
    # au moyen de la fonction "find" qui prend pour arguments:
    #     1. le chemin XPath relatif du noeud "data"
    #     2. le noeud en cours de traitement dans cette boucle foreach
    # la fonction "find" retourne par défaut une liste de noeuds, dans notre cas cette liste
    # ne contient qu'un seul élément que nous récupérons avec la fonction "get_node"
    # enfin nous en imprimons le contenu textuel au moyen de la méthode string_value
    print MATCHFILE $xpc->findvalue($form_xpath,$noeud);
    
    # Boucle d'éxtraction des formes correspondants aux éléments suivants du motif
    # On descend dans chaque noeud element du bloc
    while ( $following < $#tokens) {
      # Incrémentation du compteur $following de cette boucle d'éxtraction des formes
      $following++;
      
      # Construction du chemin XPath relatif du noeud "data" contenant
      # la forme correspondant à l'élément suivant du motif
      # Notez bien l'utilisation du compteur $folowing tant dans la condition de la boucle ci-dessus
      # que dans la construction du chemin relatif XPath
      my $following_elmt="following-sibling::element[".$following."]";      
      $form_xpath=$following_elmt."/data[\@type=\"string\"]";

      # Impression du contenu textuel du noeud data contenant la forme correspondant à l'élément suivant du motif
      print MATCHFILE " ",$xpc->findvalue($form_xpath,$noeud);
    
      # Incrémentation du compteur $following de cette boucle d'éxtraction des formes
      # $following++;
    }
    print MATCHFILE "\n";
  }
  # Fermeture du fichiers de motifs
  close(MATCHFILE);
}

Télécharger les fichiers obtenus


3° Extraction de patrons des fichiers Cordial à l'aide d'expressions régulières

Fiche technique du script :
TRAITEMENT DE LA SURFACE
Premier argument du programme : le fichier cordial
Deuxième argument du programme : le fichier patron
ENTREE : fichiers .cnr contenant les textes étiquetés en BAO2 par Cordial
SORTIE : fichiers textes comprenant les patrons extraits


#!/usr/bin/perl
#----------------------------------
# Ouverture des fichiers en lecture
#----------------------------------
open (FICTAG, $ARGV[0]) or die ("probleme sur ouverture de la sortie CORDIAL...");
open (FICPOS, $ARGV[1]) or die ("probleme sur ouverture du fichier des patrons...");
#-----------------------------------------
# on stocke les patrons dans une liste....
#-----------------------------------------
my @listedespatrons=();
while (my $lignepos = ) {
    chomp($lignepos);
    push(@listedespatrons,$lignepos);
}
close(FICPOS);
#---------------------------
# Initialisation des listes
#--------------------------
my @malignesegmentee = ();
my @listedetokens = ();
my @listedelemmes = ();
my @listedepos = ();
#-------------------------------------------
# Lecture du fichier de tags ligne par ligne
#-------------------------------------------
while (my $ligne = ) {
    #----------------------------------------------------------------------------------
    # On ne s'occupe pas des lignes qui ne respectent pas la modèle mot tab mot tab mot
    #----------------------------------------------------------------------------------
    if ($ligne =~ /^[^\t]+\t[^\t]+\t[^\t]+$/) {
  #-------------------------------------------
  # Suppression du caractère de saut de ligne
  chomp($ligne);
  #-------------------------------------------
  # Remplissage des listes
  @malignesegmentee = split(/\t/, $ligne);
  push(@listedetokens, $malignesegmentee[0]);
  push(@listedelemmes, $malignesegmentee[1]);
  push(@listedepos, $malignesegmentee[2]);
  #-------------------------------------------
    }
}
close(FICTAG);
#-----------------------------------
# on va maintenant parcourir les POS
# et les TOKENS en //
#----------------------------------------------------------------------------------------
# 1. on cree une liste tmp des POS que l'on va parcourir en supprimant le premier element 
#    a chaque fois
#----------------------------------------------------------------------------------------
my @tmplistedespos=@listedepos;
my $indice=0;
while (my $pos =shift(@tmplistedespos)) {
    foreach my $patron (@listedespatrons) {
  #-----------------------------------
  # on segmente le patron pour connaitre
  # son premier element
  my @listedeterme=split(/\#/,$patron);
  #-----------------------------------
  # on teste si l'element courant POS correspond au premier element du patron...
  if ($pos=~/$listedeterme[0]/) {
      # si c'est OK...
      # on regarde maintenant s'il y a correspondance pour la suite...
      my $verif=0;
      for (my $i=0;$i<=$#listedeterme-1;$i++) {
    if ($tmplistedespos[$i]=~/$listedeterme[$i+1]/) { 
        #Le suivant est bon aussi...
        $verif++ ;
    }
    else {
        # ici : $tmplistedespos[$i] differe de $listedeterme[$i+1]...
    }
      }
      #------------------------------------------------------------------------
      # si verif est egal au nb d'element du patron c'est qu'on a tt reconnu... 
      # on imprime les tokens en // aux POS : astuce $indice permet de garder le 
      # le // entre POS et TOKEN....
      #------------------------------------------------------------------------
      if ($verif == $#listedeterme) { 
    #print "Correspondance sur $patron \n";
    for (my $i=0;$i<=$#listedeterme;$i++) {
        print $listedetokens[$indice+$i]," ";
    }
    print "\n";
      }
  }
    }
    $indice++;
    # on avance dans la liste des POS et des TOKEN en //
}

Télécharger les fichiers obtenus



4° Extraction de patrons des fichiers xml à l'aide de feuilles xsl
(Afin d'assurer la bonne ouverture des pages suivantes, il est préférable d'utiliser FireFox et non Chrome)


Patron ADJ_NOM pour la rubrique 3208


Patron ADV_NOM pour la rubrique 3210


Patron ADV_ADJ pour la rubrique 3214


BAO4


Meryl Bothua - M1 PluriTAL - 2015-2016