{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Nous allons implanter le calcul de la distribution des mots d’un texte (son vocabu-\n",
    "laire) en fonction de leur taille en caractères.\n",
    "\n",
    "**Constitution du corpus**\n",
    "\n",
    "Récupérez les 2 fichiers textes (plain text utf-8) accessibles à l'adresse suivante :\n",
    "\n",
    "* ”Le discours de la méthode” (fr) http://www.gutenberg.org/ebooks/13846\n",
    "* ”Ulysses” (en) http://www.gutenberg.org/ebooks/4300\n",
    "\n",
    "Les enregistrer à la racine de votre Notebook dans un dossier corpus.\n",
    "\n",
    "* **lire** les textes\n",
    "* **découper** en mots (ou tokeniser)\n",
    "* **compter** le nombre de mots par taille de caractères\n",
    "* **observer** les résultats chiffrés\n",
    "* **représenter** cela sur une courbe\n",
    "\n",
    "## Etape 1: lire le texte "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import glob #glob est une librairie Python qui nous permettra de parcourir les fichiers de votre disque\n",
    "print(glob.glob(\"*\"))\n",
    "#NB: observez que c'est une liste Python"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "La **méthode** glob de la **librairie** du même nom prend en **paramètre** (entre parenthèses) un chemin (sous forme de chaîne de caractères). \n",
    "\n",
    "Ici \"*\" signifie que l'on demande à Python d'afficher tout le contenu du dossier courant. Vous n'avez pas forcément les mêmes fichiers que moi mais si vous avez bien suivi les instructions plus haut, vous avez aussi un dossier nommé corpus. \n",
    "Nous allons maintenant afficher son contenu:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(glob.glob(\"corpus/*\"))#NB: \"/\" indique que l'on va chercher dans le dossier. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "NB : Si vous êtes sous Windows vous devrez peut être écrire \"corpus\\\\\\\\*\"\n",
    "\n",
    "Maitenant ouvrons ce fichier. Observez que la **fonction** open prend trois **paramètres** : le chemin, le mode d'ouverture (\"r\" pour _read_) et l'encodage (ou encoding)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "with open(\"corpus/pg13846.txt\", \"r\", encoding = \"utf-8\") as f:\n",
    "  chaine = f.read()# La méthode read ouvre sous forme de chaîne de caractères\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Manipulation de chaînes de caractères"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Les 100 premiers caractères :\n",
    "print(chaine[:100])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Les caractèes 939 à 1089 (remarquez que l'on a les sauts de ligne):\n",
    "print(chaine[939:1089])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Les 200 derniers caractères :\n",
    "print(chaine[-200:])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Etape 2 : Découpage en mots (tokenisation)\n",
    "\n",
    "NB: sur le formatage de chaînes de caractères (\"%i\"%variable dans cet exemple puis f\"{variable}\" par la suite) vous pouvez allez regarder le lien suivant : https://stackoverflow.com/questions/5082452/string-formatting-vs-format"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#La méthode split permet de faire un découpage simple en mots. Exemple avec le segment de texte précédent :\n",
    "print(chaine[-200:].split())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Maintenant on le fait sur tout le texte mais on stocke au lieu de faire un print\n",
    "liste_mots = chaine.split()\n",
    "print(\" Le texte contient au total %i mots\" %len(liste_mots))\n",
    "# \"%i\" permet d'insérer une variable de type \"Integer\" dans une chaîne de caractères. Equivalent à :\n",
    "#print(\" Le texte contient au total \"+ str(len(liste_mots)) + \" mots\" )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Etape 3 : Comptage des mots\n",
    "On va utiliser un **dictionnaire** Python (ou tableau associatif) où l'on va stocker pour chaque longueur en caractères le nombre de mots qu'on a rencontré.\n",
    "\n",
    "L'**algorithme** est le suivant:\n",
    "* pour chaque mot de la liste de mots, on calcule sa longueur\n",
    "* on vérifie si on a déjà rencontré un mot de cette longueur:\n",
    "  * Si c'est le premier mot pour cette longueur on crée une **clé** (une entrée dans le dictionnaire) pour cette longueur à laquelle on affecte la **valeur** 1 (on a vu cette longueur de mots 1 fois)\n",
    "  * Sinon, on **incrémente** de 1 la valeur existante (on a vu cette longueur 1 fois de plus)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "## Une première version sur un échantillon:\n",
    "dic_longueurs = {} #un dictionnaire vide\n",
    "\n",
    "for mot in liste_mots[1:20]: #on prend les mots 1 à 20 (arbitraire)\n",
    "  longueur = len(mot)#la longueur du mot\n",
    "  if longueur not in dic_longueurs: #on a jamais vu cette longueur de mot\n",
    "    dic_longueurs[longueur]=1 #\n",
    "    print(f\"Premier mot de {longueur} caractères : {mot}\")\n",
    "    #NB: précéder la chaîne de f permet d'ajouter des variables dans la chaîne à partir de leur nom\n",
    "  else: #on a vu cette longueur de mot\n",
    "    dic_longueurs[longueur]+=1\n",
    "  #print(dic_longueurs)\n",
    "\n",
    "for longueur, nombre in dic_longueurs.items():\n",
    "    print(f\"On a {nombre} mots de {longueur} caractères\")\n",
    "print(dic_longueurs)#pour avoir une vue de ce qu'on a fait"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### NB: quand on va travailler sur tout le texte on ne va pas faire tous ces _print_ .  Les _print_ permettent de vérifier que ce que l'on fait marche bien"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "dic_longueurs = {} #on réinititalise le dictionnaire (i.e. pour qu'il soit vide)\n",
    "\n",
    "for mot in liste_mots: \n",
    "  longueur = len(mot)\n",
    "  if longueur not in dic_longueurs:\n",
    "    dic_longueurs[longueur]=1 #\n",
    "  else:#on a vu cette longueur de mot\n",
    "    dic_longueurs[longueur]+=1\n",
    "\n",
    "print(dic_longueurs)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Etape 4 : Observation des résultats\n",
    "\n",
    "Un dictionnaire n'est pas une **structure de données** qui peut être directement triée (ou ordonnée). Pour vérifier que'on trouve des résultats proche de l'attendu, on va afficher le nombre d'occurences enregistré dans _dic_longueurs_ pour toutes les longueurs de 1 à 30 en utilisant **l'itérateur** _range_ pour afficher dans l'ordre croissant de taille en caractères."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "for toto in range(30):\n",
    "  if toto in dic_longueurs:\n",
    "    nbr_occurences = dic_longueurs[toto]\n",
    "  else:\n",
    "    nbr_occurences = 0\n",
    "  print(f\"Longueur {toto}, {nbr_occurences} occurrences\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Etape 5 : Représentation graphique\n",
    "\n",
    "Et maintenant c'est magique, on va créer une courbe grâce à la **librairie** _pyplot_ de _matplotlib_. On va importer cette librairie et la renommer pour que ça soit plus court à écrire. Puis pour avoir les valeurs à mettre sur la courbe on va lire les valeurs dans l'ordre croissant pour les ranger dans une liste nommée _liste_effectifs_. _pyplot_ prend entrée un **vecteur** (i.e. une liste de valeurs ordonnées).\n",
    "\n",
    "NB: _il faut parfois valider deux fois la cellule suivante pour que la courbe s'affiche bien_."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as pyplot #import avec alias\n",
    "\n",
    "liste_effectifs = []\n",
    "for toto in range(30):\n",
    "  if toto in dic_longueurs:#on a donc vu des mots de cette longueur\n",
    "    liste_effectifs.append(dic_longueurs[toto])\n",
    "  else:#on en n'a pas vu de cette longueur, on ajoute donc un 0\n",
    "    liste_effectifs.append(0)\n",
    "pyplot.plot(liste_effectifs)#on \"dessine\"\n",
    "pyplot.show()#\"on affiche\"\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Maintenant si on veut faire le même calcul pour l'autre texte on a juste à changer le nom du fichier dans l'étape 1 et à relancer toutes les cellules. Mais si on avait 100 textes à faire ça ne serait pas très pratique.\n",
    "\n",
    "A vous d'essayer de voir comment améliorer le code pour traiter d'un coup, autrement dit comment **factoriser** le code en bouclant sur les tous les fichiers txt."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(glob.glob(\"corpus/*\"))\n",
    "#chemins"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for chemin in glob.glob(\"corpus/*\"):\n",
    "    print(chemin)\n",
    "    f = open(chemin, \"r\", encoding = \"utf-8\")\n",
    "    chaine = f.read()\n",
    "    f.close()\n",
    "    liste_mots = chaine .split ()\n",
    "    print(\" Le texte contient au total %i mots\" %len(liste_mots))\n",
    "    dic_longueurs = {} #on réinititalise le dictionnaire (i.e. pour qu'il soit vide)\n",
    "\n",
    "    for mot in liste_mots: \n",
    "      longueur = len(mot)\n",
    "      if longueur not in dic_longueurs:\n",
    "        dic_longueurs[longueur]=1 #\n",
    "      else:#on a vu cette longueur de mot\n",
    "        dic_longueurs[longueur]+=1\n",
    "    #print(dic_longueurs)\n",
    "    liste_effectifs = []\n",
    "    for toto in range(30):\n",
    "      if toto in dic_longueurs:#on a donc vu des mots de cette longueur\n",
    "        liste_effectifs.append(dic_longueurs[toto])\n",
    "      else:#on en n'a pas vu de cette longueur, on ajoute donc un 0\n",
    "        liste_effectifs.append(0)\n",
    "    #print(liste_effectifs)\n",
    "    pyplot.plot(liste_effectifs)#on \"dessine\"\n",
    "pyplot.show()#\"on affiche\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
