Sujet choisi :Les vœux des Présidents de la République depuis 1974
Ce sujet permet d'analyser plusieurs textes sur le même thème afin d'avoir différents points de vue et compte-rendus de la situation d'après le gouvernement et l'époque.
/*
Fichier : sae_exercice_3_b.cs
Auteur : Axel Munch
Description : Question 3 - Partie 2
*/
using System;
using System.IO;
using System.Collections.Generic;
class Nuages_de_mots
{
public static void Main()
{
// Définition des constantes / valeurs fixes :
const string CHEMIN_TEXTES = "./Textes/";
const string TEXTE_TEST = "2020 Emmanuel Macron.txt";
const string CHEMIN_MOTS_VIDES = "./mot_vide.txt";
const string CHEMIN_ET1 = "./etape1.txt";
const string CHEMIN_ET2 = "./etape2.txt";
char[] CARACTERES_IGNORES = new char[] {' ', ',', '.', '?', '!', ';', ':', '\'', '"', '&', '(', ')', '[', ']', '{', '}', '#', '~', '|', '`', '^', '¨', '@', '°', '+', '-', '=', '/', '\\', '<', '>', '€', '$', '£', '*', '%', '¤', '²'}; // Tableau 1D des caractères séparateurs
char[] VOYELLES = new char[] {'a', 'e', 'i', 'o', 'u', 'y', 'à', 'â', 'ä', 'é', 'è', 'ê', 'ë', 'ï', 'î', 'ô', 'ö', 'ù', 'û', 'ü', 'ÿ', 'æ', 'œ'};
// Récupération des lignes d'un texte de test
List<string> liste_lignes = charger_texte(CHEMIN_TEXTES + TEXTE_TEST);
// On compte les occurence des mots à partir des lignes
Dictionary<string, int> occurences_mots = compter_occurences(liste_lignes, CARACTERES_IGNORES);
// Suppression des caractères vides
occurences_mots = supprimer_vides(occurences_mots, CHEMIN_MOTS_VIDES);
// On normalise les mots du texte avec les racines
occurences_mots = normalisation(occurences_mots, CHEMIN_ET1, CHEMIN_ET2, VOYELLES);
// Affichage du résultat
afficher_dictionnaire(occurences_mots);
}
/*
charger_texte : function : List<string>
Charge un fichier depuis l'ordinateur à l'emplacement Xchemin et renvoie une liste contenant les lignes de ce fichier
paramètres:
Xchemin : string : Chemin dans l'arborescence jusqu'au fichier à ouvrir
local:
liste_lignes : List<string> : Liste qui contient les lignes du texte sous forme de chaînes de caractères
texte : StreamReader : Instance du fichier texte
ligne : string : Ligne actuelle lors du parcours du texte
retour:
liste_lignes : List<string> : Liste qui contient les lignes du texte sous forme de chaînes de caractères
*/
public static List<string> charger_texte(string Xchemin)
{
// Liste vide qui contiendra les lignes du fichier
List<string> liste_lignes = new List<string>();
// Ouverture du fichier en lecture (On suppose que l'utilisateur a entré un chemin valide)
StreamReader texte = new StreamReader(Xchemin);
string ligne;
// Tant qu'on peut affecter une nouvelle ligne du fichier à ligne
while((ligne = texte.ReadLine()) != null)
{
// On ajoute la ligne dans la liste
liste_lignes.Add(ligne);
}
// On ferme le fichier texte
texte.Close();
return liste_lignes;
}
/*
compter_occurences : function : Dictionary<string, int>
Compte le nombre d'occurences de chaque mot dans une liste de chaînes de caractères et les renvoie dans un dictionnaire
paramètres:
Xliste_mots : List<string> : Liste de lignes sous forme de chaîne de caractères
CARACTERES_IGNORES : char[] : Tableau des caractères à séparer
local:
occurences_mots : Dictionary<string, int> : Liste qui contient les lignes du texte sous forme de chaînes de caractères
mots : string[] : Tableau contenant les mots de chaque ligne séparés par CARACTERES_IGNORES
mot_minuscules : string : Mot parcouru converti en minuscules (pour les comparaisons plus tard)
i : int : Compteur
j : int : Compteur
retour:
occurences_mots : Dictionary<string, int> : Dictionnaire qui a comme clés les mots du texte et comme valeurs le nombre d'occurences de chaque mot dans le texte
*/
public static Dictionary<string, int> compter_occurences(List<string> Xliste_mots, char[] CARACTERES_IGNORES)
{
// Création du dictionnaire à renvoyer
Dictionary<string, int> occurences_mots = new Dictionary<string, int>();
string[] mots;
string mot_minuscules;
// Pour chaque ligne dans Xliste_mots
for(int i = 0; i < Xliste_mots.Count; i++)
{
// Sépare les caractères de la ligne par les séparateurs
mots = Xliste_mots[i].Split(CARACTERES_IGNORES);
// On parcourt chaque mot
for(int j = 0; j < mots.Length; j++)
{
// Transformation du mot en lettres minuscules
mot_minuscules = mots[j].ToLower();
// Si le dictionnaire ne contient pas encore une entrée pour le mot
if(!occurences_mots.ContainsKey(mot_minuscules))
{
// On ajoute la clé mot_minuscules avec une valeur de 0
occurences_mots.Add(mot_minuscules, 0);
}
// On incrémente le nombre d'occurences du mot dans le dictionnaire
occurences_mots[mot_minuscules] += 1;
}
}
return occurences_mots;
}
/*
afficher_dictionnaire : proc : void
Affiche un dictionnaire sous la forme de valeur : clé
paramètres:
Xoccurences_mots : Dictionary<string, int> : Dictionnaire qui a comme clés les mots du texte et comme valeurs le nombre d'occurences de chaque mot dans le texte
local:
kvp : KeyValuePair<string, int> : Couple des clés et valeurs dans le parcours du dictionnaire
*/
public static void afficher_dictionnaire(Dictionary<string, int> Xoccurences_mots)
{
// On parcourt le dictionnaire
foreach(KeyValuePair<string, int> kvp in Xoccurences_mots)
{
// On affiche la valeur puis la clé de chaque entrée du dictionnaire avec une chaîne formatée
Console.WriteLine("{0} :\t{1}", kvp.Value, kvp.Key);
}
}
/*
supprimer_vides : function : Dictionary<string, int>
Supprime les mots qui n'apportent pas d'informations sur le contenu dans un dictionnaire
paramètres:
Xoccurences_mots : Dictionary<string, int> : Dictionnaire qui a comme clés les mots du texte et comme valeurs le nombre d'occurences de chaque mot dans le texte
CHEMIN_MOTS_VIDES : string : Chemin vers le fichier des mots vides
local:
dictionnaire_non_vide : Dictionary<string, int> : Dictionnaire de retour qui ne contient pas les mots vides
mots_vides : List<string> : Liste des mots vides
kvp : KeyValuePair<string, int> : Couple des clés et valeurs dans le parcours du dictionnaire
retour:
dictionnaire_non_vide : Dictionary<string, int> : Dictionnaire de retour qui ne contient pas les mots vides
*/
public static Dictionary<string, int> supprimer_vides(Dictionary<string, int> Xoccurences_mots, string CHEMIN_MOTS_VIDES)
{
// Création du ductionnaire de retour
Dictionary<string, int> dictionnaire_non_vide = new Dictionary<string, int>();
// Chargement des mots vides
List<string> mots_vides = charger_texte(CHEMIN_MOTS_VIDES);
// On parcourt le dictionnaire
foreach(KeyValuePair<string, int> kvp in Xoccurences_mots)
{
// Si le mot parcouru n'est pas dans les mots vides
if(!mots_vides.Contains(kvp.Key))
{
// On l'ajoute au dictionnaire de retour
dictionnaire_non_vide.Add(kvp.Key, kvp.Value);
}
}
return dictionnaire_non_vide;
}
/*
min : function : int
Renvoie le minimum entre deux nombres
paramètres:
Xa : int : Premier nombre
Xb : int : Deuxième nombre
local:
minimum : int : Minimum entre Xa et Xb
retour:
minimum : int : Minimum entre Xa et Xb
*/
public static int min(int Xa, int Xb)
{
int minimum;
if(Xa > Xb)
{
minimum = Xb;
}
else
{
minimum = Xa;
}
return minimum;
}
/*
contient_suffixe : function : bool
Renvoie vrai ou faux si la chaîne 1 termine par la chaîne 2
paramètres:
Xch1 : string : Première chaîne
Xch2 : string : Deuxième chaîne
local:
contient : bool : Booléen de retour
retour:
contient : bool : Booléen de retour
*/
public static bool contient_suffixe(string Xch1, string Xch2)
{
bool contient = false;
if(Xch2.Length <= Xch1.Length)
{
contient = true;
for(int i = 0; i < min(Xch1.Length, Xch2.Length) && contient; i++)
{
if(!(Xch1[Xch1.Length - 1 - i] == Xch2[Xch2.Length - 1 - i]))
{
contient = false;
}
}
}
return contient;
}
/*
enlever_fin : function : string
Renvoie la début d'une chaîne de caractères jusqu'au caractère d'indice Xtaille_enlever
paramètres:
Xch : string : Chaîne de caractères
Xtaille_enlever : int : Taille de la chaîne à conserver
retour:
string : Début de la chaîne jusqu'à l'indice Xtaille_enlever
*/
public static string enlever_fin(string Xch, int Xtaille_enlever)
{
return Xch.Substring(0, Xch.Length - Xtaille_enlever);
}
/*
charger_etape : proc : void
Charge un fichier de règles et le mets dans le dictionnaire Xetapes directement dans la mémoire
paramètres:
Xetapes : Dictionary<string, string[]> : Dictionnaire qui contient les lignes coupées
CHEMIN_ET : string : Chemin vers le fichier de l'étape à ouvrir
local:
ligne_split : string[] : Tableau de chaîne de caractères qui contient les lignes coupées par l'espace
*/
public static void charger_etape(Dictionary<string, string[]> Xetapes, string CHEMIN_ET)
{
string[] ligne_split;
foreach(string ligne in charger_texte(CHEMIN_ET))
{
ligne_split = ligne.Split(' ');
if(!Xetapes.ContainsKey(ligne_split[1]))
{
Xetapes.Add(ligne_split[1], new string[0]);
}
Xetapes[ligne_split[1]] = ligne_split;
}
}
/*
est_voyelle : function : bool
Renvoie vrai ou faux si le tableau de caractères contient une voyelle dont la liste est envoyée en argument
paramètres:
Xtab : char[] : Tableau de caractères
Xelement : char : Caractère à rechercher
local:
contient : bool : Booléen de retour
retour:
contient : bool : Booléen de retour
*/
public static bool est_voyelle(char[] Xtab, char Xelement)
{
bool contient = false;
for(int i = 0; i < Xtab.Length && !contient; i++)
{
if(Xtab[i] == Xelement)
{
contient = true;
}
}
return contient;
}
/*
est_voyelle : function : bool
Renvoie le nombre d'occurences de la suite VC (Voyelles Consonnes) dans un mot
paramètres:
Xmot : string : Mot à analyser
VOYELLES : char[] : Tableau des voyelles accentuées
local:
m : double : Nombre d'occurences de la suite VC dans le mot
retour:
int : Nombre d'occurences de la suite VC dans le mot
*/
public static int compter_vc(string Xmot, char[] VOYELLES)
{
double m = 0;
foreach(char c in Xmot)
{
// Si c'est une voyelle
if(est_voyelle(VOYELLES, c) && m % 1 == 0)
{
m += 0.5;
}
// Si c'est une consonne
else if(!est_voyelle(VOYELLES, c) && m % 1 == 0.5)
{
m += 0.5;
}
}
return (int)m;
}
/*
normalisation : function : Dictionary<string, int>
Supprime les terminaisons inutiles des mots en appliquant certaines règles
paramètres:
Xoccurences_mots : Dictionary<string, int> : Dictionnaire qui a comme clés les mots du texte et comme valeurs le nombre d'occurences de chaque mot dans le texte
CHEMIN_ET1 : string : Chemin vers le fichier de l'étape 1
CHEMIN_ET2 : string : Chemin vers le fichier de l'étape 2
VOYELLES : char[] : Tableau des voyelles accentuées
local:
mots_normalises : Dictionary<string, int> : Dictionnaire contenant les mots normalisés et leur nombre d'apparitions
etapes : Dictionary<string, string[]> : Dictionnaire temporaire contenant les étapes
suffixes_separes : List<string[]> : Liste de tableaux qui contient les règles
kvp : KeyValuePair<string, int> : Couple des clés et valeurs dans le parcours du dictionnaire
mot_observe : string : Mot actuel lors du parcours de la boucle
trouve : bool : Booléen vrai si on a trouvé une racine pour une certaine valeur dans la boucle
retour:
mots_normalises : Dictionary<string, int> : Dictionnaire contenant les mots normalisés et leur nombre d'apparitions
*/
public static Dictionary<string, int> normalisation(Dictionary<string, int> Xoccurences_mots, string CHEMIN_ET1, string CHEMIN_ET2, char[] VOYELLES)
{
Dictionary<string, int> mots_normalises = new Dictionary<string, int>();
// Il y a des éléments en double dans les différentes étapes, donc on change pour un dictionnaire qui permettra de facilement gérer les doublons
Dictionary<string, string[]> etapes = new Dictionary<string, string[]>();
List<string[]> suffixes_separes = new List<string[]>();
// On charge les étapes
charger_etape(etapes, CHEMIN_ET1);
charger_etape(etapes, CHEMIN_ET2);
// On convertit le dictionnaire en liste
foreach(KeyValuePair<string, string[]> kvp in etapes)
{
suffixes_separes.Add(kvp.Value);
}
// On libère la mémoire, la variable ne sert plus
etapes.Clear();
string mot_observe;
bool trouve;
// On parcourt le dictionnaire
foreach(KeyValuePair<string, int> kvp in Xoccurences_mots)
{
mot_observe = kvp.Key;
// On réinitialise la variable "trouvé" pour la boucle
trouve = false;
// Recherche de la racine en parcourant tous les suffixes
for(int i = 0; i < suffixes_separes.Count && !trouve; i++)
{
// Si on trouve une racine
if(contient_suffixe(mot_observe, suffixes_separes[i][1]))
{
// Variable pour sortir de la boucle
trouve = true;
// On retire la fin du mot
mot_observe = enlever_fin(mot_observe, suffixes_separes[i][1].Length);
// On vérifie la validité de la terminaison
if(compter_vc(mot_observe, VOYELLES) > int.Parse(suffixes_separes[i][0]))
{
// Si la règle n'est pas epsilon
if(suffixes_separes[i][2].CompareTo("epsilon") != 0)
{
// On ajoute la terminaison
mot_observe += suffixes_separes[i][2];
}
}
else
{
// Si la terminaison n'est pas valide, on affecte le mot original au mot observé
mot_observe = kvp.Key;
}
}
}
// Si le dictionnaire ne contient pas encore une entrée pour le mot
if(!mots_normalises.ContainsKey(mot_observe))
{
// On ajoute la clé mot_observe avec une valeur de 0
mots_normalises.Add(mot_observe, 0);
}
// On incrémente le nombre d'occurences du mot dans le dictionnaire
mots_normalises[mot_observe] += kvp.Value;
}
return mots_normalises;
}
}
Les mots plus importants dans les discours ont une taille supérieure aux autres et sont à l'avant-plan.
Le survol d'un mot avec le curseur le met en avant pour une meilleure visibilité en cas de superposition et affiche son nombre d'occurences dans les textes analysés.
Grâce à l'algorithme de placement des mots dans le nuage, aucun n'est placé à la même position, ils devraient donc tous être accessibles pendant la navigation.
Il y a 256 couleurs de mots générées aléatoirement disponibles pour les nuages. Chacune de ces couleurs contient du bleu pour rappeler le thème de couleur du site.