#MODE D'EMPLOI DU PROGRAMME : perl bao2-parcours-etiquetage.pl nom_dossier numero_rubrique

#-----------------------------------------------------------

#/usr/bin/perl

#On précise qu'on veut utiliser l'encodage UTF-8.
use utf8;

#On précise qu'on veut utiliser le mode strict qui va limiter certains fonctionnalités qui ne nous sont pas utiles et qui risquent de créer des bugs.
use strict;

#On précise que la sortie sur le terminal est en UTF-8.
binmode(STDOUT, ":encoding(UTF-8)");

#@ARGV est la liste des arguments données au programme. # permet d'obtenir la longueur de la liste qui est un scalaire (d'où le $).
#Si la longueur de la liste des arguments est différent de 1, ça signifie qu'il manque un argument.
#On rappelle qu'une longueur de 1 signifie qu'il y a deux éléments dans la liste : celui à l'index 0 et celui à l'index 1.
if ($#ARGV != 1) {print "Il manque un argument à votre programme....\n";exit;}

#L'argument d'index 0 de la liste d'arguments, le nom du dossier, est mis dans la variable $rep.
my $rep="$ARGV[0]";

#L'argument d'index 1, le numéro de la rubrique choisie, est mis dans la variable $RUBRIQUE.
my $RUBRIQUE="$ARGV[1]";

#Pour normaliser le nom des répéertoires, on enlève, grâce à la "s" et en ne mettant rien dans la deuxième paire de slash, tous les / de fin de ligne.
$rep=~ s/[\/]$//;

#On ouvre en écriture (comme le montre le chevron fermant >) un fichier TXT qu'on appelle "corpus-titre-description" suivi du numéro de la rubrique.
open my $txt, ">:encoding(UTF-8)","corpus-titre-description-$RUBRIQUE.txt";

#On ouvre en écriture un fichier XML. Ce fichier sera une sorte de fichier "tampon", un fichier temporaire. Ce sera un pré-corpus des titres et descriptions avec un token par ligne. Il servira pour l'annotation avec TreeTagger plus tard.
open my $xml, ">:encoding(UTF-8)","pre-corpus-titre-description-$RUBRIQUE.xml";

#On écrit l'entête du fichier XML (version et encodage) ainsi que la balise racine <corpus>.
print $xml "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<corpus>\n";

#On lance le sous-programme &parcoursarborescencefichiers sur notre dossier ($rep). Cette fonction est définie plus bas.
&parcoursarborescencefichiers($rep);

#On écrit la balise fermante de </corpus> dans le fichier XML, sans quoi ce dernier ne serait pas bien formé.
print $xml "</corpus>\n";

#On ferme les fichiers TXT et XML.
close $txt;
close $xml;

#On lance l'étiquetage avec UDpipe sur le fichier TXT (corpus-titre-description_$RUBRIQUE.txt).
#Ce sous-programme est défini plus bas.
&etiquetageUP;

#On lance l'annotation avec TreeTagger sur le fichier XML (pre-corpus-titre-description_$RUBRIQUE.xml).
#Ce sous-programme est défini plus bas.
&etiquetageTT;

#Le programme est fini.
exit;

#-----------------------------------------------------------

#On définit la fonction pour l'étiquetage avec UDpipe. Il prendra en entrée le fichier texte brut : il y a un titre et une description par ligne.
sub etiquetageUP {

	#La fonction "system()" permet d'écrire dans le terminal à partir d'un script Perl.
	#On exécute le programme UDpipe (udpipe.exe) en indiquant son chemin par rapport à notre répertoire courant.
	#On tokenize le texte (option --tokenize).
	#On l'annote en Part of Speech (option --tag).
	#On l'annote en dépendence syntaxique (option --parse).
	#On indique, avec l'option "--tokenizer=presegmented", que le texte est déjà segmenté avec une phrase par ligne.
	#On renvoie le résultat dans un fichier au format CoNLL nommé corpus-titre-description.udpipe.
	system("./distrib-udpipe-1.2.0-bin/udpipe-1.2.0-bin/bin-win32/udpipe.exe --tokenize --tag --parse --tokenizer=presegmented ./distrib-udpipe-1.2.0-bin/modeles/french-sequoia-ud-2.5-191206.udpipe corpus-titre-description-$RUBRIQUE.txt > corpus-annotation-ud-$RUBRIQUE.udpipe");

	#On lance le programme "udpipe2xml-version-sans-titrevsdescription-v2.pl" qui va permettre de reformater le fichier CoNLL au format XML. On a besoin de ça pour la BAO3 et l'extraction des relations de dépendance.
	system("perl ./distrib-udpipe-1.2.0-bin/udpipe2xml-version-sans-titrevsdescription-v2.pl corpus-annotation-ud-$RUBRIQUE.udpipe");
}

#-----------------------------------------------------------

#On définit la fonction &etiquetageTT qui va prendre en entrée le pré-corpus XML avec un token par ligne.
sub etiquetageTT {

	#La fonction "system()" permet d'écrire sur le terminal à partir d'un script Perl.
	#On exécute le programme TreeTagger (tree-tagger.exe) en indiquant son chemin relatif par rapport à notre répertoire courant.
	#On lemmatise le texte (option -lemma).
	#On le tokenize (-token).
	#L'option "-no-unknown" permet d'indiquer qu'on ne veut pas qu'il soit affiché "unknown" si jamais le lemme n'est pas reconnu par TreeTagger.
	#On met le résultat dans corpus-titre-description. On ne met pas encore d'extension car on doit d'abord formaté le fichier TreeTagger au format XML.
	system("./distrib-treetagger/tree-tagger.exe -lemma -token -no-unknown -sgml ./distrib-treetagger/french-utf8.par  pre-corpus-titre-description-$RUBRIQUE.xml  >  corpus-annotation-tt-$RUBRIQUE ");

	#On repasse par le terminal avec "system()". On utilise le programme "treetagger2xml-utf8.pl" pour formater le fichier renvoyé par TreeTagger au format XML avec un encodage UTF-8.
	system("perl ./distrib-treetagger/treetagger2xml-utf8.pl corpus-annotation-tt-$RUBRIQUE UTF8");

}

#----------------------------------------------

#On définit la fonction récursive &parcoursarborescencefichiers qui va permettre de parcourir tous les fichiers RSS et d'en extraire le contenu textuel souhaité.
sub parcoursarborescencefichiers {

	#On enlève le premier élément de la liste d'arguments, c'est-à-dire le nom du répertoire. On le met dans la varibale $path.
    my $path = shift(@_);

	#On ouvre le dossier avec la fonction opendir(). On précise que c'est un dossier avec "DIR" car la première fois que l'on rentre dans l'arborescence, on arrive forcément sur un dossier.
	#Si ça ne marche pas, on va afficher sur le terminal "Impossible d'ouvrir..."
	opendir(DIR, $path) or die "Impossible d'ouvrir $path: $!\n";

	#On lit tous les noms des éléments du dossier avec la fonction readdir(DIR).
	#On met tout dans la liste @files.
    my @files = readdir(DIR);

	#On ferme le dossier.
    closedir(DIR);

	#Pour chaque fichier ($file) de la liste @files) :
    foreach my $file (@files) {

		#On ne traite pas (next if) ceux qui matchent . ou .. car ce sont respectivement un moyen de référer au dossier courant et au dossier parent.
		next if $file =~ /^\.\.?$/;

		#Si ce n'est pas . ou .., le nom de l'élément devient son nom précédé d'un / et du nom contenu dans la variable $path. Cela va permettre de renommer chaque fichier/dossier par son chemin relatif par rapport au premier dossier ouvert.
		$file = $path."/".$file;

		#-d (directory) renvoie True si l'élément est un dossier.
		if (-d $file) {

			#Si l'élément est un dossier, on imprime sur le terminal "On entre dans le REPERTOIRE : ...".
			print "On entre dans le REPERTOIRE : $file \n";

			#On relance la fonction &parcoursarborescencefichiers avec cette fois-ci en entrée le nouveau dossier.
			#C'est une fonction récursive car elle fait appel à elle-même.
			&parcoursarborescencefichiers($file);

			#On affiche sur le terminal "On sort du REPERTOIRE..."
			print "On sort du REPERTOIRE :  $file \n";
		}

		#-f (file) renvoie True si l'élément est un fichier.
		if (-f $file) {

			#Si le nom du fichier contient le numéro de la rubrique avec l'extension .xml :
			if ($file =~ /$RUBRIQUE.+\.xml$/) {

				#On affiche sur le terminal "Traitement du fichier..."
				print "Traitement du fichier $file \n";

				#On ouvre le fichier en lecture, comme le montre le chevron ouvrant <.
				open my $input, "<:encoding(UTF-8)",$file;

				#Par défaut, la variable $/ contient un retour à la ligne (\n). Quand on le undef, on enlève cette valeur par défaut.
				$/=undef;

				#Comme on a undef $/, on peut lire le fichier dans sa globalité avec <$input>. Sinon, on devrait le lire ligne par ligne.
				#On met le contenu entier du fichier dans la variable $ligne.
				my $ligne=<$input> ;

				#On ferme le fichier RSS.
				close($input);

				#Les titres des articles se trouvent dans les balises <title>...</title>. On indique que la balise <title> doit obligatoirement être précédé d'une balise ouvrante <item>.
				#En effet, il existe dans le fichier RSS une autre balise <title> précédée d'une balise ouvrante <channel> et qui elle contient le nom du Journal Le Monde suivi du nom de la rubrique.
				#Ce titre-là ne nous intéresse pas. En rajoutant <item>, on l'écarte des matchs.
				#La description, elle, se trouve dans la balise <description>...</description>.
				#Les parenthèses permettent de capturer le contenu textuel pour pouvoir le réutiliser.
				while ($ligne=~/<item><title>(.+?)<\/title>.+?<description>(.+?)<\/description>/gs) {

					#On fait passer le groupe de capture 1 ($1), le titre, dans le sous-programme &nettoyage.
					#On met le résultat dans la variable $titre.
					my $titre=&nettoyage($1);

					#On fait la même chose avec le deuxième groupe de capture ($2), la description, qu'on met dans la variable $description.
					my $description=&nettoyage($2);

					#On écrit dans notre TXT le titre nettoyé suivi d'un retour à la ligne (\n).
					print $txt "$titre \n";

					#On écrit dans le TXT la description nettoyée suivie d'un retour à la ligne.
					print $txt "$description \n";

					#On sépare les couples de titre-description par des tirets pour la lisibilité.
					print $txt "-----------------\n";

					#On fait passer le titre et la description par le sous-programme &segmentationTD qui est défini plus loin.
					#On met les résultats respectivement dans $titreSEG et $descriptionSEG.
					my ($titreSEG,$descriptionSEG)=&segmentationTD($titre,$description);

					#On écrit dans notre XML le titre segmenté dans des balises <titre>...</titre> et la description dans des balises <description>...</description>.
					#Le couple titre-description est mis dans des balises <item>...</item>.
					print $xml "<item><titre>\n$titreSEG\n</titre><description>\n$descriptionSEG\n</description></item>\n";
				}
			}
		}
    }
}

#-----------------------------------------------------------

#On définit la fonction qui va permettre de segmenter le texte en un token par ligne. Ce résultat sera mis dans le fichier de pré-corpus XML qui sera utilisé ensuite pour l'annotation par TreeTagger.
sub segmentationTD {

	#Le sous-programme prend en entrée deux arguments : le titre nettoyé et la description nettoyée.
	#On met le titre dans la variable $arg1 et la description dans la variable $arg2.
	my ($arg1,$arg2)=@_;

	#Pour segmenter, on va faire appel à TreeTagger via le terminal.
	#Cependant, TreeTagger ne peut pas prendre en entrée une variable, seulement un fichier texte.
	#On doit donc créer un fichier texte "tampon" ($tmp).
	#On ouvre le fichier en écriture, comme l'indique le chevron fermant >, avec encodage UTF-8. On l'appelle tampon.txt.
	open my $tmp, ">:encoding(UTF-8)","tampon.txt";

	#On écrit dans notre fichier tampon le titre.
	print $tmp $arg1;

	#On ferme le fichier tampon.
	close $tmp;

	#La fonction "system()" permet d'écrire dans le terminal via un script Perl.
	#On exécute le programme "tokenize-utf8.pl" et on renvoie le résultat dans un deuxième fichier "tampon" nommée tampon2.txt
	system("perl ./distrib-treetagger/tokenise-utf8.pl tampon.txt > tampon2.txt");

	#Par défaut, la variable $/ contient un retour à la ligne. On le undef pour pouvoir lire le fichier dans sa globalité et pas ligne par ligne.
	undef $/;

	#On ouvre le deuxième fichier tampon en lecture, comme l'indique le chevron ouvrant <, avec encodage UTF-8.
	open my $tmp2, "<:encoding(UTF-8)","tampon2.txt";

	#On lit l'intégralité du fichier, avec <$...> et on met le contenu dans la variable $titresegmente.
	my $titresegmente=<$tmp2>;

	#On ferme tampon2.txt.
	close $tmp2;

	#On recommence la même procédure mais cette-fois-ci avec le deuxième argument donné au sous-programme : la description.
	open $tmp, ">:encoding(UTF-8)","tampon.txt";
	print $tmp $arg2;
	close $tmp;
	system("perl ./distrib-treetagger/tokenise-utf8.pl tampon.txt > tampon2.txt");
	open  $tmp2, "<:encoding(UTF-8)","tampon2.txt";
	my $descriptionsegmente=<$tmp2>;
	close $tmp2;

	#On redéfinit $/ pour la suite du programme.
	$/="\n";

	#La fonction renvoie le titre avec un token par ligne et la description avec un token par ligne.
	return $titresegmente,$descriptionsegmente;
}

#-----------------------------------------------------------

#On définit le sous-programme pour le nettoyage du texte.
#Le contenu textuel que nous voulions reccueillir se trouve dans des balises <![CDATA[..]]>. Ces balises permettent de déspécialiser tout ce qui se trouve à l'intérieur pour ne pas que le contenu soit interprété comme des balises XML.
sub nettoyage {

	#On récupère le premier argument de la liste d'arguments (@_), c'est-à-dire le titre ou la description.
	my $texte=shift @_;

	#On remplace grâce à "s" toutes les balises CDATA par rien.
	$texte=~s/(^<!\[CDATA\[)|(\]\]>$)//g;

	#On rajoute (avec ".=") un point à la fin du titre ou de la description. Cela va aider UDpipe à annoter.
	$texte.=".";

	#Si le titre ou la description se finissait déjà par un ., on risque d'avoir deux points d'affilé.
	#On remplace donc tous les points par un seul point.
	$texte=~s/\.+$/\./;

	#On renvoie le texte nettoyé.
	return $texte;
}
#----------------------------------------------
