Elise LINCKER

Boîte à outils 2

Etiquetage morpho-syntaxique

Objectif

La deuxième boîte à outils vise à enrichir la première boîte à outils de sorte que les fichiers de sortie soient annotés morpho-syntaxiquement.

Pour cela, nous reprenons le code de la boîte à outils 1 et y ajoutons une étape consacrée à l'étiquetage. Nous avons utilisé les deux étiqueteurs suivants :

Les script mis au point renvoient cinq fichiers. Ils génèrent aussi des fichiers intermédiaires dont nous ne tiendrons pas compte dans le cadre de ce travail. Les deux premiers fichiers sont identiques aux sorties de la première boîte à outils, ils correspondent au contenu textuel seul des titres et des descriptions. Les autres fichiers correspondent aux sorties des outils d'étiquetage appliqués sur ce contenu textuel. Sont lancés les programmes treetagger2xml et udpipe2xml pour reformater les sorties des étiqueteurs au format XML. Ces sorties seront utilisées pour les traitement de la boîte à outils 3.

Réflexions

Nous nous sommes posés la question suivante : comment mettre en oeuvre l'annotation ? A la volée, après extraction du titre et de la description de chaque item, ou bien sur la concaténation de tous les items, en une seule fois ? Il paraît évident qu'un étiquetage global est plus performant et plus rapide. Nous avons tout de même décidé d'essayer les deux méthodes pour ensuite comparer les résultats et les temps d'exécution des programmes.

D'autre part, nous avons constaté des difficultés de la part des étiqueteurs utilisés concernant le traitement de certains symboles comme l'apostrophe et l'esperluette. Il est nécessaire de compléter la procédure de nettoyage, nous avons encore fait en sorte que l'esperluette "&" soit sous forme de symbole dans les fichiers TXT et sous forme d'entité HTML dans les fichiers XML pour que ceux-ci soient bien formés.

Méthode 1 : étiquetage global

#/usr/bin/perl
<<DOC; 
Nom -- Elise LINCKER
Date -- MARS 2021

Traitement -- parcours d une arborescence de fichiers (fil RSS)
              extraction du contenu textuel des balises TITLE et DESCRIPTION avec les expressions régulières
              nettoyage du contenu textuel
              étiquetage morpho-syntaxique avec TreeTagger et UDpipe sur l ensemble des données extraites (en 1 fois, à la fin)

Utilisation du programme -- perl bao2_regexp_etiquetage_global.pl REPERTOIRE_A_PARCOURIR RUBRIQUE_A_TRAITER
Entrée -- le nom du répertoire-racine contenant les fichiers à traiter
          et le nom de la rubrique à traiter parmi ces fichiers
Sortie -- un fichier TXT, même sortie que celle de la BAO1
          un fichier XML, même sortie que celle de la BAO1
          un fichier intermédiaire, sortie TreeTagger
          un fichier XML, sortie d étiquetage TreeTagger
          un fichier TXT au format CONLL, sortie d étiquetage UDpipe
          un fichier XML, fichier CONLL étiquetage UDpipe reformaté en XML
DOC
#-----------------------------------------------------------
use strict;
use utf8;
use Timer::Simple;
# on instancie un timer commencant à 0.0s par défaut
my $t = Timer::Simple->new();
# on lance le timer
$t->start;

#-----------------------------------------------------------
# on récupère le nom du répertoire racine de l'arborescence à traiter
my $rep="$ARGV[0]";
# on récupère le nom de la rubrique à traiter
my $rubrique ="$ARGV[1]";

# on s'assure que le nom du répertoire ne se termine pas par un "/", sinon on enlève le "/"
$rep=~ s/[\/]$//;

# déclaration-initialisation des fichiers de sortie
open my $OUT,">:encoding(utf8)","BAO2_sortie_$rubrique.txt";
open my $OUTXML,">:encoding(utf8)","BAO2_sortieXML_int_$rubrique.xml";
open my $OUTXMLOK,">:encoding(utf8)","BAO2_sortieXML_$rubrique.xml";
open my $OUTUDPIPE,">:encoding(utf8)","BAO2_sortieUDpipe_$rubrique.txt";

# dans le fichier XML, écritute de l'en-tête XML et ouverture de la balise racine
print $OUTXML "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n";
print $OUTXML "<articles>\n";
print $OUTXMLOK "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n";
print $OUTXMLOK "<articles>\n";

# initialisation de compteurs et d'une table de hachage
my %dico_des_titres=();
my $numberItem=0;
my $nbFile=0;

#----------------------------------------
# on déclenche la procédure parcoursarborescencefichiers (récursivité !) en prenant 
# comme argument le nom du répertoire racine par lequel on doit commencer le parcours
&parcoursarborescencefichiers($rep);

#----------------------------------------
# dans le fichier XML, fermeture de la balise racine
print $OUTXML "</articles>\n";
print $OUTXMLOK "</articles>\n";

# fermeture des fichiers de sortie
close $OUT;
close $OUTXML;
close $OUTXMLOK;
close $OUTUDPIPE;

#----------------------------------------
# on déclenche les procédures etiquetageTT et etiquetageUD
&etiquetageTT;
&etiquetageUD;
&UDpipe2XML;

#----------------------------------------------
print "Nb item : $numberItem \n";
# affichage du temps écoulé depuis le lancement du programme
print "Time so far: ", $t->elapsed, " seconds\n";

# fin de l'exécution du programme
exit;

#----------------------------------------------
# procédure parcoursarborescencefichiers
# on accède au contenu du dossier dans lequel on se trouve
sub parcoursarborescencefichiers {

	# on récupère l'argument passé à la procédure (le nom de dossier)
	my $path = shift(@_);
	
	# ouverture du répertoire avec la fonction perl opendir :
	# elle prend comme arguments : le nom du répertoire à ouvrir 
	# + un descripteur, qui va être à partir de maintenant le moyen d'accéder au répertoire qu'on a ouvert
	opendir(my $DIRhandle, $path) or die "can't open $path: $!\n";
	
	# lecture du répertoire avec la fonction perl readdir :
	# elle prend comme argument le descripteur du répertoire qu'on vient d'ouvrir
	# et renvoie comme valeur la liste des fichiers contenus dans le répertoire
	# on stocke cette liste dans @files
	my @files = readdir($DIRhandle);

	# fermeture du répertoire
	closedir($DIRhandle);

	# pour chaque élément contenu dans le répertoire (ficher ou répertoire)
	foreach my $file (@files) {
		# on passe au fichier suivant s'il s'agit d'un répertoire caché
		next if $file =~ /^\.\.?$/;

		# reconstruction du chemin relatif de l'élément traité $file
		$file = $path."/".$file;
		# "." est un opérateur de concaténation : "2020"."/"."01" => "2020/01"

		# on teste le statut du fichier avec les opérateurs -d et - f
		
		# -d ---> true si $file est un répertoire 
		if (-d $file) {
			# on relance la procédure parcoursarborescencefichiers sur le répertoire $file
			&parcoursarborescencefichiers($file);	# recursivité !
		}
		
		# -f ---> true si $file est un fichier
		if (-f $file) {

			# on veut récupérer des fichiers XML RSS et une seule rubrique en particuler :
			# si le nom du fichier correspond au nom de la RUBRIQUE qu'on veut traiter
			# ET se termine par l'EXTENSION .xml ---> ON TRAITE LE FICHIER !
			if ($file =~/$rubrique.+xml$/) {
			
				# incrémentation du compteur de fichiers + message dans le terminal du fichier traité
				print $nbFile++," Traitement de : ",$file,"\n";

				# **************** TRAITEMENT DE LA BAO 1 : PERL REGEPX ****************
				# ****************     EXTRACTION DU CONTENU TEXTUEL    ****************

				# ouverture et lecture du fichier jusqu'à la fin en une seule fois
				open my $fic,"<:encoding(utf8)",$file;
				$/=undef;     #ou $\=""
				my $textelu=<$fic>;
				# fermeture du fichier
				close $fic;

				# boucle qui extrait les titres et descriptions à l'aide des expressions régulières
				while ($textelu=~/<item>.*?<title>(.+?)<\/title>.+?<description>(.+?)<\/description>/sg) {
					# initialisation des variables $titre et $description pour traiter les titres et descriptions séparément 
					my $titre=$1;
					my $description=$2;

					# incrémentation du compteur d'items
					$numberItem++;

					# appel de la procédure de nettoyage 
					($titre,$description)=&nettoyage($titre,$description);

					# si le titre n'existe pas dans la table de hachage $dico_des_titres, 
					if (!(exists $dico_des_titres{$titre})) { 
						# alors ce n'est pas un doublon : on ajoute le titre et sa description à la table de hachage
						$dico_des_titres{$titre}=$description ;

						# écriture des résultats dans les fichiers de sortie
						print $OUT "$titre\n";
						print $OUT "$description\n";
						print $OUT "--\n";

						# on distingue le fichier XML qui va servir à TreeTagger :
						print $OUTXML "<item>\n";
						print $OUTXML "<titre>$titre</titre>\n";
						print $OUTXML "<description>$description</description>\n";
						print $OUTXML "</item>\n";

						# et le fichier XML propre de sortie --> attention pour que ce fichier soit bien formé, il faut écrire "&" sous la forme de son entité
						$titre=~s/&/&/g;
						$description=~s/&/&/g;
						print $OUTXMLOK "<item>\n";
						print $OUTXMLOK "<titre>$titre</titre>\n";
						print $OUTXMLOK "<description>$description</description>\n";
						print $OUTXMLOK "</item>\n";
					}
					
					# si le titre est déjà dans $dico_des_titres, on ne fait rien
				}
			}
		}
	}
}

#----------------------------------------------
# procédure nettoyage
sub nettoyage {
    #my $titre=shift(@_); autre solution en vidant la liste des arguments du programmes...
    #my $description=shift(@_);
    my $titre = $_[0];
    my $description = $_[1];
	$titre=~s/^<!\[CDATA\[//;
	$titre=~s/\]\]>$//;
	$description=~s/^<!\[CDATA\[//;
	$description=~s/\]\]>$//;
    $description=~s/<.+?>//g;
    $description=~s/&#39;/'/g;
    $description=~s/&#34;/"/g;
	$description=~s/&/&/g;
	$description=~s/’/'/g;
	$description=~s/\s\s+/ /g;
	$titre=~s/<.+?>//g;
    $titre=~s/&#39;/'/g;
    $titre=~s/&#34;/"/g;
	$titre=~s/&/&/g;
	$titre=~s/’/'/g;
	$titre=~s/\s\s+/ /g;
    $titre=~s/$/\./g;
	$titre=~s/\.+$/\./g;
	
    return $titre,$description;
}

# *******************     TRAITEMENT DE LA BAO 2     *******************
# *******************  ETIQUETAGE MORPHO-SYNTAXIQUE  *******************

#----------------------------------------------
# procédure etiquetageTT -- étiquetage avec TreeTagger
sub etiquetageTT {
# ceci se fait en deux étapes : on construit d'abord un fichier intermédiaire qui contiendra chaque mot
# (tokenisé, 1 token par ligne), et son annotation
#   --> pour cela on fait appel au programme perl de tokenisation tokenise-utf8.pl
#       puis à l'exécutable tree-tagger, on spécifie les options -token -lemma -no-unknown -sgml
    system ("perl -f ./tree-tagger-linux-3.2/tokenise-utf8.pl BAO2_sortieXML_int_$rubrique.xml | ./tree-tagger-linux-3.2/tree-tagger ./tree-tagger-linux-3.2/french-utf8.par -token -lemma -no-unknown -sgml > BAO2_sortieXML_TreeTagger_$rubrique");
# puis à partir de ce fichier tokenisé et annoté intermédiaire, on fait un reformatage du fichier en XML
# avec les balises XML qui permettent de repérer pour chaque élément sa catégorie, son lemme et sa forme
#   --> pour cela on fait appel au programme perl treetagger2xml-utf8.pl
	system ("perl ./tree-tagger-linux-3.2/treetagger2xml-utf8.pl BAO2_sortieXML_TreeTagger_$rubrique utf8"); 
}

#-----------------------------------------------
# procédure etiquetageUD -- étiquetage avec UDpipe :
# fait appel à l'exécutable udpipe, utilisation du modèle de langue French GSD UD version 2.5
sub etiquetageUD {
	system("./udpipe-1.2.0/bin-linux64/udpipe --tokenize --tokenizer=presegmented --tag --parse ./udpipe-1.2.0/french-gsd-ud-2.5-191206.udpipe BAO2_sortie_$rubrique.txt > BAO2_sortieUDpipe_$rubrique.txt");
}

#-----------------------------------------------
# procédure reformatage UDpipe -> XML :
# à partir du fichier de sortie UDPipe au format CONLL, on fait un reformatage du fichier en XML
#   --> pour cela on fait appel au programme perl udpipe2xml-version-sans-titrevsdescription-v3.pl
sub UDpipe2XML {
	system("perl ./udpipe2xml/udpipe2xml-version-sans-titrevsdescription-v2.pl BAO2_sortieUDpipe_$rubrique.txt");
}

Méthode 2 : étiquetage à la volée

#/usr/bin/perl
<<DOC; 
Nom -- Elise LINCKER
Date -- MARS 2021

Traitement -- parcours d une arborescence de fichiers (fil RSS)
              extraction du contenu textuel des balises TITLE et DESCRIPTION avec les expressions régulières
              nettoyage du contenu textuel
              étiquetage morpho-syntaxique avec TreeTagger et UDpipe après chaque extraction d 1 titre et 1 description

Utilisation du programme -- perl bao2_regexp_etiquetage_global.pl REPERTOIRE_A_PARCOURIR RUBRIQUE_A_TRAITER
Entrée -- le nom du répertoire-racine contenant les fichiers à traiter
          et le nom de la rubrique à traiter parmi ces fichiers
Sortie -- un fichier TXT, même sortie que celle de la BAO1
          un fichier XML, même sortie que celle de la BAO1
          un fichier XML, sortie d étiquetage TreeTagger
          un fichier TXT au format CONLL, sortie d étiquetage UDpipe
          un fichier XML, sortie d étiquetage UDpipe reformaté en XML
DOC
#-----------------------------------------------------------
use strict;
use utf8;
use Timer::Simple;
# on instancie un timer commencant à 0.0s par défaut
my $t = Timer::Simple->new();
# on lance le timer
$t->start;

#-----------------------------------------------------------
# on récupère le nom du répertoire racine de l'arborescence à traiter
my $rep="$ARGV[0]";
# on récupère le nom de la rubrique à traiter
my $rubrique ="$ARGV[1]";

# on s'assure que le nom du répertoire ne se termine pas par un "/", sinon on enlève le "/"
$rep=~ s/[\/]$//;

# déclaration-initialisation des fichiers de sortie
open my $OUT,">:encoding(utf8)","BAO2_sortie_$rubrique.txt";
open my $OUTXML,">:encoding(utf8)","BAO2_sortieXML_$rubrique.xml";
open my $OUTXMLOK,">:encoding(utf8)","BAO2_sortieXML_$rubrique.xml";
open my $OUTUDPIPE,">:encoding(utf8)","BAO2_sortieUDpipe_$rubrique.txt";
open my $OUTUDPIPEXML,">:encoding(utf8)","BAO2_sortieUDpipe_$rubrique.xml";
open my $OUTTREETAGGER,">:encoding(utf8)","BAO2_sortieXML_TreeTagger_$rubrique.xml";

# dans le fichier XML, écritute de l'en-tête XML et ouverture de la balise racine
print $OUTXML "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n";
print $OUTXML "<articles rubrique=\"$rubrique\">\n";
print $OUTXMLOK "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n";
print $OUTXMLOK "<articles rubrique=\"$rubrique\">\n";
print $OUTUDPIPEXML "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n";
print $OUTUDPIPEXML "<articles rubrique=\"$rubrique\">\n";
print $OUTTREETAGGER "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n";
print $OUTTREETAGGER "<articles rubrique=\"$rubrique\">\n";

# initialisation de compteurs et d'une table de hachage
my %dico_des_titres=();
my $numberItem=0;
my $nbFile=0;

#----------------------------------------
# on déclenche la procédure parcoursarborescencefichiers (récursivité !) en prenant 
# comme argument le nom du répertoire racine par lequel on doit commencer le parcours
&parcoursarborescencefichiers($rep);

#----------------------------------------
# dans le fichier XML, fermeture de la balise racine
print $OUTXML "</articles>\n";
print $OUTXMLOK "</articles>\n";
print $OUTUDPIPEXML "</articles>\n";
print $OUTTREETAGGER "</articles>\n";

# fermeture des fichiers de sortie
close $OUT;
close $OUTXML;
close $OUTXMLOK;
close $OUTUDPIPE;
close $OUTUDPIPEXML;
close $OUTTREETAGGER;

#----------------------------------------------
print "Nb item : $numberItem \n";
# affichage du temps écoulé depuis le lancement du programme
print "Time so far: ", $t->elapsed, " seconds\n";

# fin de l'exécution du programme
exit;

#----------------------------------------------
# procédure parcoursarborescencefichiers
# on accède au contenu du dossier dans lequel on se trouve
sub parcoursarborescencefichiers {

	# on récupère l'argument passé à la procédure (le nom de dossier)
	my $path = shift(@_);
	
	# ouverture du répertoire avec la fonction perl opendir :
	# elle prend comme arguments : le nom du répertoire à ouvrir 
	# + un descripteur, qui va être à partir de maintenant le moyen d'accéder au répertoire qu'on a ouvert
	opendir(my $DIRhandle, $path) or die "can't open $path: $!\n";
	
	# lecture du répertoire avec la fonction perl readdir :
	# elle prend comme argument le descripteur du répertoire qu'on vient d'ouvrir
	# et renvoie comme valeur la liste des fichiers contenus dans le répertoire
	# on stocke cette liste dans @files
	my @files = readdir($DIRhandle);

	# fermeture du répertoire
	closedir($DIRhandle);

	# pour chaque élément contenu dans le répertoire (ficher ou répertoire)
	foreach my $file (@files) {
		# on passe au fichier suivant s'il s'agit d'un répertoire caché
		next if $file =~ /^\.\.?$/;

		# reconstruction du chemin relatif de l'élément traité $file
		$file = $path."/".$file;
		# "." est un opérateur de concaténation : "2020"."/"."01" => "2020/01"

		# on teste le statut du fichier avec les opérateurs -d et - f
		
		# -d ---> true si $file est un répertoire 
		if (-d $file) {
			# on relance la procédure parcoursarborescencefichiers sur le répertoire $file
			&parcoursarborescencefichiers($file);	# recursivité !
		}
		
		# -f ---> true si $file est un fichier
		if (-f $file) {

			# on veut récupérer des fichiers XML RSS et une seule rubrique en particuler :
			# si le nom du fichier correspond au nom de la RUBRIQUE qu'on veut traiter
			# ET se termine par l'EXTENSION .xml ---> ON TRAITE LE FICHIER !
			if ($file =~/$rubrique.+xml$/) {
			
				# incrémentation du compteur de fichiers + message dans le terminal du fichier traité
				print $nbFile++," Traitement de : ",$file,"\n";

				# **************** TRAITEMENT DE LA BAO 1 : PERL REGEPX ****************
				# ****************     EXTRACTION DU CONTENU TEXTUEL    ****************

				# ouverture et lecture du fichier jusqu'à la fin en une seule fois
				open my $fic,"<:encoding(utf8)",$file;
				$/=undef;     #ou $\=""
				my $textelu=<$fic>;
				# fermeture du fichier
				close $fic;

				# boucle qui extrait les titres et descriptions à l'aide des expressions régulières
				while ($textelu=~/<item>.*?<title>(.+?)<\/title>.+?<description>(.+?)<\/description>/sg) {
					# initialisation des variables $titre et $description pour traiter les titres et descriptions séparément 
					my $titre=$1;
					my $description=$2;

					# incrémentation du compteur d'items
					$numberItem++;

					# appel de la procédure de nettoyage 
					($titre,$description)=&nettoyage($titre,$description);

					# si le titre n'existe pas dans la table de hachage $dico_des_titres, 
					if (!(exists $dico_des_titres{$titre})) { 
						# alors ce n'est pas un doublon : on ajoute le titre et sa description à la table de hachage
						$dico_des_titres{$titre}=$description ;

						# écriture des résultats dans les fichiers de sortie et déclenchement des procédures etiquetageUD et etiquetageTT
						print $OUT "$titre\n";
						print $OUT "$description\n";
						print $OUT "--\n";

						my ($titre_description_UDPipe,$titre_description_UDPipe_XML) = &etiquetageUD($titre, $description);
						print $OUTUDPIPE "$titre_description_UDPipe\n";
						print $OUTUDPIPEXML "$titre_description_UDPipe_XML\n";

						# on distingue le fichier XML qui va servir à TreeTagger :
						print $OUTXML "<item>\n";
						print $OUTXML "<titre>$titre</titre>\n";
						print $OUTXML "<description>$description</description>\n";
						print $OUTXML "</item>\n";

						my ($titre_TT, $description_TT) = &etiquetageTT($titre, $description);
						print $OUTTREETAGGER "<item number=\"$numberItem\">\n<titre>\n$titre_TT</titre>\n<description>\n$description_TT</description>\n</item>\n";

						# et le fichier XML propre de sortie --> attention pour que ce fichier soit bien formé, il faut écrire "&" sous la forme de son entité
						$titre=~s/&/&/g;
						$description=~s/&/&/g;
						print $OUTXMLOK "<item>\n";
						print $OUTXMLOK "<titre>$titre</titre>\n";
						print $OUTXMLOK "<description>$description</description>\n";
						print $OUTXMLOK "</item>\n";
					}

					# si le titre est déjà dans $dico_des_titres, on ne fait rien
				}
			}
		}
	}
}

#----------------------------------------------
# procédure nettoyage
sub nettoyage {
	#my $titre=shift(@_); autre solution en vidant la liste des arguments du programmes...
	#my $description=shift(@_);
	my $titre = $_[0];
	my $description = $_[1];
	$titre=~s/^<!\[CDATA\[//;
	$titre=~s/\]\]>$//;
	$description=~s/^<!\[CDATA\[//;
	$description=~s/\]\]>$//;
	$description=~s/<.+?>//g;
	$description=~s/&#39;/'/g;
	$description=~s/&#34;/"/g;
	$description=~s/&/&/g;
	$description=~s/’/'/g;
	$description=~s/\s\s+/ /g;
	$titre=~s/<.+?>//g;
	$titre=~s/&#39;/'/g;
	$titre=~s/&#34;/"/g;
	$titre=~s/&/&/g;
	$titre=~s/’/'/g;
	$titre=~s/\s\s+/ /g;
	$titre=~s/$/\./g;
	$titre=~s/\.+$/\./g;
	
	return $titre,$description;
}

# *******************     TRAITEMENT DE LA BAO 2     *******************
# *******************  ETIQUETAGE MORPHO-SYNTAXIQUE  *******************

#----------------------------------------------
# procédure etiquetageTT -- étiquetage avec TreeTagger
sub etiquetageTT {
	# on récupère le titre et la description à étiqueter entrés en arguments
	my $titre=shift @_;
	my $description=shift @_;

	# on traite d'une part le titre :
	# on crée un fichier temporaire dans lequel on écrit le titre à étiqueter
	open my $TITRETEMP,">:encoding(utf8)","fichier_temporaire.txt";
	print $TITRETEMP $titre;
	# on lance TreeTagger sur ce fichier temporaire
	# ceci se fait en deux étapes : on construit d'abord un fichier intermédiaire qui contiendra chaque mot
	# (tokenisé, 1 token par ligne), et son annotation
	#   --> pour cela on fait appel au programme perl de tokenisation tokenise-utf8.pl
	#       puis à l'exécutable tree-tagger, on spécifie les options -token -lemma -no-unknown -sgml
	system ("perl -f ./tree-tagger-linux-3.2/tokenise-utf8.pl fichier_temporaire.txt | ./tree-tagger-linux-3.2/tree-tagger ./tree-tagger-linux-3.2/french-utf8.par -token -lemma -no-unknown -sgml > fichier_temporaire_TreeTagger");
	# puis à partir de ce fichier tokenisé et annoté intermédiaire, on fait un reformatage du fichier en XML
	# avec les balises XML qui permettent de repérer pour chaque élément sa catégorie, son lemme et sa forme
	#   --> pour cela on fait appel au programme perl treetagger2xml-utf8.pl
	system ("perl ./tree-tagger-linux-3.2/treetagger2xml-utf8.pl fichier_temporaire_TreeTagger utf8"); 
	# on lit le fichier temporaire de sortie
	open my $OUTTITRETEMP,"<:encoding(utf8)","fichier_temporaire_TreeTagger.xml";
	$/=undef;     #ou $\=""
	my $out_titre_TT=<$OUTTITRETEMP>;
	# on enlève l'en-tête XML (on la remplace par rien)
	$out_titre_TT=~s/<\?xml version="1\.0" encoding="utf-8" standalone="no"\?>\r?\n?//;
	
	# puis on traite la description (mêmes traitements) :
	# on crée un fichier temporaire dans lequel on écrit la description à étiqueter
	open my $DESCRIPTIONTEMP,">:encoding(utf8)","fichier_temporaire.txt";
	print $DESCRIPTIONTEMP $description;
	# on lance TreeTagger sur ce fichier temporaire
	system ("perl -f ./tree-tagger-linux-3.2/tokenise-utf8.pl fichier_temporaire.txt | ./tree-tagger-linux-3.2/tree-tagger ./tree-tagger-linux-3.2/french-utf8.par -token -lemma -no-unknown -sgml > fichier_temporaire_TreeTagger");
	# on lance treetagger2xml-utf8.pl
	system ("perl ./tree-tagger-linux-3.2/treetagger2xml-utf8.pl fichier_temporaire_TreeTagger utf8"); 
	# on lit le fichier temporaire de sortie
	open my $OUTDESCRIPTIONTEMP,"<:encoding(utf8)","fichier_temporaire_TreeTagger.xml";
	$/=undef;     #ou $\=""
	my $out_description_TT=<$OUTDESCRIPTIONTEMP>;
	# on enlève l'en-tête XML (on la remplace par rien)
	$out_description_TT=~s/<\?xml version="1\.0" encoding="utf-8" standalone="no"\?>\r?\n?//;

	return $out_titre_TT,$out_description_TT;
}

#-----------------------------------------------
# procédure etiquetageUD -- étiquetage avec UDpipe :
# fait appel à l'exécutable udpipe, utilisation du modèle de langue French GSD UD version 2.5
sub etiquetageUD {
	# on récupère le titre et la description à étiqueter entrés en arguments
	my $titre=shift @_;
	my $description=shift @_;
	# on crée un fichier temporaire dans lequel on écrit le titre et la description à étiqueter
	open my $TEMP,">:encoding(utf8)","fichier_temporaire.txt";
	print $TEMP "$titre\n";
	print $TEMP "$description\n";
	# on lance UDPipe sur ce fichier temporaire, on obtient en sortie un nouveau fichier temporaire
	system("./udpipe-1.2.0/bin-linux64/udpipe --tokenize --tokenizer=presegmented --tag --parse ./udpipe-1.2.0/french-gsd-ud-2.5-191206.udpipe fichier_temporaire.txt > fichier_temporaire_UDPipe.txt");
	# on lit le fichier temporaire de sortie
	open my $OUTTEMP,"<:encoding(utf8)","fichier_temporaire_UDPipe.txt";
	$/=undef;     #ou $\=""
	my $out_UDPipe=<$OUTTEMP>;
	# on enlève l'en-tête du fichier
	$out_UDPipe=~s/# newdoc id = fichier_temporaire.txt\n//g;
	# on reformate en XML
	#   --> pour cela on fait appel au programme perl treetagger2xml-utf8.pl
	system("perl ./udpipe2xml/udpipe2xml-version-sans-titrevsdescription-v2.pl fichier_temporaire_UDPipe.txt");
	# on lit le fichier temporaire de sortie
	open my $OUTUDXMLTEMP,"<:encoding(utf8)","fichier_temporaire_UDPipe.txt.xml";
	$/=undef;     #ou $\=""
	my $out_UDPipeXML=<$OUTUDXMLTEMP>;
	# on enlève l'en-tête XML (on la remplace par rien)
	$out_UDPipeXML=~s/<\?xml version="1\.0" encoding="utf-8"\?>\r?\n?//;
	$out_UDPipeXML=~s/<baseudpipe>\n//;
	$out_UDPipeXML=~s/<\/baseudpipe>\n//;
	return $out_UDPipe,$out_UDPipeXML;
}

Résultats

Comparons les temps de traitement des deux programmes sur chacune des rubriques traitées :

Temps d'exécution des programmes
RUBRIQUE METHODE
GLOBAL A LA VOLEE
Europe - 3214 104.773569 s 7028.803004 s
Planète - 3244 178.556458 s 11866.039558 s
Culture - 3246 132.738639 s 9509.563753 s
Cinéma - 3476 27.50512 s 1923.388633 s

Sur notre machine, l'étiquetage à la volée de la rubrique Planète a nécessité plus de 3 heures et quart de traitement, contre moins de 3 minutes pour un étiquetage global. Cet écart est non négligeable.
Notre hypothèse de départ est confirmée : la deuxième méthode (étiquetage des titres et des descriptions à la volée, directement après extraction) prend un temps considérablement long, du fait de l'appel répété de chacun des étiqueteurs et programmes de reformatage en XML. Les performances sont de loin meilleures lorsqu'on lance les étiqueteurs une seule fois, sur un gros corpus, plutôt que plusieurs fois sur quelques phrases.

Les sorties TreeTagger obtenues par ces deux programmes sont identiques, la seule différence étant la numérotation des balises <item>. Les sorties UDPipe CONLL et XML sont différentes de par l'organisation des phrases dans les fichiers (les numéros dans le fichier CONLL sont différents, et on a un item de séparation entre chaque article avec la méthode d'étiquetage global), mais ceci ne pose pas de problème pour la suite des traitements. Pour un même étiqueteur, l'étiquetage morpho-syntaxique des titres et des descriptions est le même peu importe la méthode utilisée.

Vous pouvez télécharger les fichiers de sortie obtenus après étiquetage, ainsi que l'ensemble des fichiers de sortie, depuis le tableau ci-dessous :

Sorties après étiquetage
RUBRIQUE ETIQUETAGE GLOBAL ETIQUETAGE A LA VOLEE
TREETAGGER XML UDPIPE CONLL UDPIPE XML TREETAGGER XML UDPIPE CONLL UDPIPE XML
Europe - 3214 icone-de-telechargement icone-de-telechargement icone-de-telechargement icone-de-telechargement icone-de-telechargement icone-de-telechargement
Planète - 3244 icone-de-telechargement icone-de-telechargement icone-de-telechargement icone-de-telechargement icone-de-telechargement icone-de-telechargement
Culture - 3246 icone-de-telechargement icone-de-telechargement icone-de-telechargement icone-de-telechargement icone-de-telechargement icone-de-telechargement
Cinéma - 3476 icone-de-telechargement icone-de-telechargement icone-de-telechargement icone-de-telechargement icone-de-telechargement icone-de-telechargement
Tout icone-de-telechargement