Boîte à Outils 2 - Etiqueter le texte extrait du Fil RSS du Monde

La boîte à Outils 2 récupère le code de la première boîte à Outils mais y ajoute l'étiquetage des données avec TreeTagger et UDpipe. On peut adapter le sript présenté ici pour ne pas refaire l'étape de récupération des données et de repartir directement des fichiers en sortie par le premier script en y ajoutant tout de même la fonction de segmentation.

On fera a nouveau en parallèle un script Python équivalent :

Free HTML5 Bootstrap Template by FreeHTML5.co

Le script PERL

On ne fait qu'ajouter au script de la Boîte à Outils 1 les fonctions

  • etiquetageTT
  • etiquetageUP
  • et
  • segmentationTD
pour former ce script Perl.

sub segmentationTD {
	my $texte=shift @_;
	open my $tmp, ">:encoding(UTF-8)","DonneeText.txt";
	print $tmp $texte;
	close $tmp;
	system("perl ./distrib-treetagger/tokenise-utf8.pl DonneeText.txt > DonneeTok.txt");
	undef $/;
	open my $tmp2, "<:encoding(UTF-8)","DonneeTok.txt";
	my $textesegmente=<$tmp2>;
	close $tmp2;
	return $textesegmente;
}

La fonction segmentationTD prend comme argument le texte à segmenter. Ici le titre et la description. La première étape de la fonction est donc de récupérer le paramètre dans une nouvelle variable qui sera utilisée à l'echelle locale.

Les données textuelles des titres et des descriptions sont passée succésivement dans la fonction qui est traite les données textuelles avec le tokeniseur de TreeTagger que l'on appelle grâce à la commande system à laquelle on donne ensuite une ligne de commande bash.

Le contenu du fichier de sortie, c'est à dire le texte tokenisé, est ensuite récupéré. On peut recommencer pour le nombre de données textuelles souhaité

On peut ensuite le résultat des titres et des descriptions segmentées dans le fichier xml de sortie. La fonction segmentationTD est ajoutée directement dans la fonction de parcours d'arborescence des fichiers

my $titreSEG=&segmentationTD($titre);
my $descriptionSEG=&segmentationTD($description);
print $output_xml "<item><titre>\n$titreSEG\n</titre><description>\n$descriptionSEG\n</description></item>\n";
sub etiquetageUP {
	system("./distrib-udpipe/udpipe-1.2.0-bin/bin-linux64/udpipe --tokenize --tag --parse --tokenizer=presegmented ./distrib-udpipe/modeles/french-sequoia-ud-2.5-191206.udpipe corpus-titre-description.txt > corpus-titre-description.udpipe");
	system("perl ./distrib-udpipe/udpipe2xml.pl corpus-titre-description.udpipe");
}

Pour étiquetter les textes, on utilise directement les commandes bash grâce à system.

On commence par traiter le texte avec UDpipe en appellant l'executable du dossier distrib-udpipe adapté au système d'exploitation de la machine (linux64 dans mon cas). Ce fichier est ensuite post-traité par notre script perl qui transforme la sortie de UDpipe en un fichier XML contenu dans le même dossier distrib-udpipe.

Le fichier udpipe2xml.pl

open(INPUT,"<:encoding(utf-8)",$ARGV[0]);
open(OUTPUT,">:encoding(utf-8)","$ARGV[0].xml");

print OUTPUT "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n";
print OUTPUT "<corpus>\n";
while (my $ligne=<INPUT>) {
	
	next if ($ligne=~/^$/);
	$ligne=~s/\r//g;
		
	if ($ligne=~/^# sent_id = ([0-9]*[13579])$/){
		my $a1 = $1;
		if($a1=~/^1$/){
			print OUTPUT "<item>\n<titre>\n";
		}else{
			   print OUTPUT "<\/description>\n<\/item>\n<item>\n<titre>\n";
		}
	}

	if ($ligne=~/^\#\ssent_id\s=\s[0-9]*[02468]$/){
		
		  print OUTPUT "<\/titre>\n<description>\n";
	}
	if ($ligne=~/^([^\t]*)\t([^\t]*)\t([^\t]*)\t([^\t]*)\t[^\t]*)\t([^\t]*)\t([^\t]*)\t([^\t]*)\t([^\t]*)\t([^\t]*)$/) {
		print OUTPUT "<element>";
		print OUTPUT "<id>$1<\/id>";
		print OUTPUT "<data type=\"string\">$2<\/data>";
		print OUTPUT "<data type=\"lemma\">$3<\/data>";
		print OUTPUT "<data type=\"type\">$4<\/data>";
		print OUTPUT "<data type=\"ID_GOV\">$7<\/data>";
		print OUTPUT "<data type=\"relation\">$8<\/data>";
		print OUTPUT "<\/element>\n";
	}
}
close(INPUT);
print OUTPUT "</description>\n</item>\n</corpus>\n";
close(OUTPUT);

On décide de ne pas récupérer les groupes de capture 5,6,9 et 10 pour alléger le fichier car ces données ne sont pas utilisées dans notre projet.

On applique le même process avec TreeTagger en appliquant la commande bash au fichier pre-corpus-titre-description.xml.

On va chercher dans le dossier distrib-treetagger l'executable de treeTagger et la bibliothèque pour le français. On met le résultat dans un fichier corpus-titre-description

Comme pour UDpipe, on a mit au point un script pour automatiquement transformer le fichier de sortie de la commande précédente en XML valide et bien formé : le script treetagger2xml-utf8-global.

sub etiquetageTT {
system("./distrib-treetagger/bin/tree-tagger -lemma -token -no-unknown -sgml ./distrib-treetagger/lib/french.par  pre-corpus-titre-description.xml  >  corpus-titre-description ");
system("perl ./distrib-treetagger/treetagger2xml-utf8-global.pl corpus-titre-description UTF8");
							
						}

Le fichier treetagger2xml-utf8-global.pl

#!/usr/bin/perl
use Unicode::String qw(utf8);
<<DOC;
Format d\'entree : un texte étiqueté et lemmatisé par tree tagger et un format d'encodage
Format de Sortie : le même texte au format xml (en utf-8)
DOC


# Usage
$ChaineUsage="Usage : tt2xml.pl <Fichier> <encodage>\n";
if (@ARGV!=2) {
 die $ChaineUsage;
}

&ouvre;
&entete;
&traitement;
&fin;
&ferme;

##############################################################################################
# Récupération des arguments et ouverture des tampons
sub ouvre {
	$FichierEntree=$ARGV[0];
	$encodage=$ARGV[1];
	open(Entree,"<:encoding($encodage)",$FichierEntree);
	$FichierSortie=$FichierEntree . ".xml";
	open(Sortie,">:encoding(utf-8)",$FichierSortie);
}

# Entête de document XML
sub entete {
	print Sortie "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"no\"?>\n";
	#print Sortie "<article>\n";
}

# Traitement
sub traitement {
	while ($Ligne = <Entree>) {
	chomp($Ligne);
	next if ($Ligne=~/<?xml/);
	$Ligne=~s/\r//g;
	if (uc($encodage) ne "UTF-8") {utf8($Ligne);}
	if ($Ligne!~/\ô\¯\:\\ô\¯\:\\/) {
	# Remplacement des guillemets par <![CDATA["]]> (évite erreur d'interprétation XML)
		$Ligne=~s/\"/<![CDATA[\"]]>/g;
		$Ligne=~s/([^\t]*)\t([^\t]*)\t(.*)/<element><data type=\"type\">$2<\/data><data type=\"lemma\">$3<\/data><data type=\"string\">$1<\/data><\/element>/;
		$Ligne=~s/<unknown>/unknown/g;
		print Sortie $Ligne,"\n";
	}
	}
}
# Fin de fichier
sub fin {
	#print Sortie "</article>\n";
}

# Fermeture des tampons
sub ferme {
	close(Entree);
	close(Sortie);
}

Le script Python

On peut baser ce script python sur le code de la Boîte à Outils 1. Comme pour le script Perl, on ne fait qu'ajouter les nouvelles fonctions :

  • etiquetageTT
  • etiquetageUP
  • et
  • segmentationTD

def segmentationTD(texte):
	tmp=open("DonneeText.txt","w")
	tmp.write(texte)
	tmp.close()
	os.system("perl ./distrib-treetagger/tokenise-utf8.pl DonneeText.txt > DonneeTok.txt")
	tmp2=open("DonneeTok.txt","r")
	texteSegmente=tmp2.read()
	tmp2.close()
	return texteSegmente

Le fonction de segmentation Python ressemble beaucoup à la subroutine Perl. Contrairement à Perl, on n'est aps obligé de lire le fichier ligne par ligne avec <fichier> mais on peut lire directement l'ensemble du fichier avec la méthode fichier.read(). L'appel a des executables se fait presque de la même façon avec la fonction os.system qui execute la commande dans le terminal.

Les fonctions etiquetageTT et etiquetageUP étant très similaire aux focntions Perl, je ne les explique pas plus que dans la première partie concernant le Perl. On notera simplement qu'on utilise la bibliothèque os pour executer les commandes directement dans le système.

def etiquetageUP():
	os.system(r"./distrib-udpipe/udpipe-1.2.0-bin/bin-linux64/udpipe --tokenize --tag --parse --tokenizer=presegmented ./distrib-udpipe/modeles/french-sequoia-ud-2.5-191206.udpipe corpus-titre-description_versionPython.txt > corpus-titre-description_versionPython.udpipe")
	os.system(r"perl ./distrib-udpipe/udpipe2xml.pl corpus-titre-description_versionPython.udpipe")
def etiquetageTT():
	os.system(r"./distrib-treetagger/bin/tree-tagger -lemma -token -no-unknown -sgml ./distrib-treetagger/lib/french.par  pre-corpus-titre-description_versionPython.xml  >  corpus-titre-description_versionPython ")
	os.system(r"perl ./distrib-treetagger/treetagger2xml-utf8-global.pl corpus-titre-description_versionPython UTF8")

Le résultat






On obtient en résultat les fichiers xml de la BAO1 étiquetés par UDPipe ou TreeTagger











Projet réalisé par Eve Sauvage

En première année de Master Traitement Automatique des Langues