with open("moliere_avare.txt", "r", encoding="utf-8") as f:
texte = f.read()
print(texte[:500]) # affiche les 500 premiers caractères pour vérifier
import re
import unicodedata
from collections import defaultdict, Counter
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams["figure.figsize"] = (9, 5)
def strip_accents(s: str) -> str:
return ''.join(c for c in unicodedata.normalize('NFD', s)
if unicodedata.category(c) != 'Mn')
def normalize_name(raw: str) -> str:
s = raw.strip()
s = s.replace('’', "'")
s = s.replace('ſ', 's') # vieilles ligatures éventuelles
s = strip_accents(s).upper()
s = re.sub(r'[^A-Z\- ]+', '', s) # garde lettres/espaces/tirets
s = re.sub(r'\s+', ' ', s).strip()
return s
def word_count(text: str) -> int:
# enlève didascalies [ ... ] ( ... ) et tirets de réplique
text = re.sub(r'\[[^\]]*\]', ' ', text)
text = re.sub(r'\([^)]*\)', ' ', text)
text = text.replace('–', ' ')
tokens = re.findall(r"[A-Za-zÀ-ÖØ-öø-ÿ']+", text)
return len(tokens)
with open("moliere_avare.txt", "r", encoding="utf-8") as f:
raw = f.read()
# normalisation minimale
raw = raw.replace('\r\n', '\n').replace('\r', '\n')
acte = "INCONNU"
scene = "INCONNUE"
# compte global par personnage
wc_by_char = Counter()
# compte par personnage ET par scène
wc_by_char_scene = defaultdict(int)
lines = raw.split('\n')
i = 0
while i < len(lines):
line = lines[i].strip()
# titres d'acte / scène (markdown)
m_acte = re.match(r'^\s*##+\s*Acte\b\s*(.*)$', line, flags=re.I)
m_scene = re.match(r'^\s*###+\s*Sc[eè]ne\b\s*(.*)$', line, flags=re.I)
if m_acte:
suffix = m_acte.group(1).strip()
acte = f"ACTE {suffix or '?'}"
i += 1
continue
if m_scene:
suffix = m_scene.group(1).strip()
scene = f"SCENE {suffix or '?'}"
i += 1
continue
# ligne de locuteur (MAJUSCULES + point)
m_speaker = re.match(r"^([A-ZÉÈÀÂÎÔÛÄËÏÖÜÇŒÆ'\- ]+)\.\s*$", line)
if m_speaker:
raw_name = m_speaker.group(1)
name = normalize_name(raw_name)
# récupérer la réplique (lignes suivantes jusqu'à ligne vide ou nouveau locuteur/titre)
i += 1
speech_lines = []
while i < len(lines):
nxt = lines[i]
if not nxt.strip():
break
if re.match(r'^\s*##+', nxt): # nouveau titre acte/scène
break
if re.match(r"^([A-ZÉÈÀÂÎÔÛÄËÏÖÜÇŒÆ'\- ]+)\.\s*$", nxt.strip()):
break
speech_lines.append(nxt)
i += 1
speech = "\n".join(speech_lines)
n = word_count(speech)
if n > 0:
wc_by_char[name] += n
key_scene = f"{acte} • {scene}"
wc_by_char_scene[(name, key_scene)] += n
continue
i += 1
# DataFrames
df_total = pd.DataFrame(list(wc_by_char.items()), columns=["personnage", "mots"])\
.sort_values("mots", ascending=False).reset_index(drop=True)
df_scene = pd.DataFrame(list(wc_by_char_scene.items()), columns=["pair", "mots"])
df_scene[["personnage", "scene"]] = pd.DataFrame(df_scene["pair"].tolist(), index=df_scene.index)
df_scene = df_scene.drop(columns=["pair"])
print(type(wc_by_char), len(wc_by_char))
print(list(wc_by_char.items())[:5]) # aperçu des 5 premiers
topN = 10 # nombre de personnages à afficher
ax = df_total.head(topN).iloc[::-1].plot(
kind="barh",
x="personnage",
y="mots",
color="cornflowerblue",
legend=False
)
ax.set_xlabel("Nombre de mots prononcés")
ax.set_ylabel("")
ax.set_title(f"L'Avare — Top {topN} orateurs")
plt.tight_layout()
plt.savefig("avare_top_orateurs.png", dpi=150)
plt.show()
main_chars = set(df_total.head(5)["personnage"])
tmp = df_scene.copy()
tmp["perso_grp"] = np.where(tmp["personnage"].isin(main_chars), tmp["personnage"], "AUTRES")
pivot = tmp.pivot_table(index="scene", columns="perso_grp", values="mots", aggfunc="sum").fillna(0)
pivot = pivot.reindex(sorted(pivot.index), axis=0)
pivot.plot(kind="bar", stacked=True, figsize=(12,6))
plt.xlabel("Scènes")
plt.ylabel("Mots prononcés")
plt.title("Répartition par scène (personnages principaux)")
plt.tight_layout()
plt.savefig("avare_par_scene.png", dpi=150)
plt.show()
idx = df_scene.groupby("scene")["mots"].idxmax()
df_winner = df_scene.loc[idx, ["scene", "personnage", "mots"]].sort_values("scene")
df_winner.head(20)
Ce document propose une exploration computationnelle du texte de L’Avare, en s’appuyant sur les données disponibles sur le site de l’OBVIL. L’objectif est d’analyser la répartition de la parole entre les personnages — en particulier la quantité de mots prononcés, leur distribution selon les scènes, et la dynamique d’interlocution implicite.
Cette approche vise à relier les structures littéraires visibles (le texte, les dialogues) à des structures invisibles : rapports de pouvoir, densité psychologique des scènes, et hiérarchie dramatique implicite.
import re, pandas as pd, numpy as np, matplotlib.pyplot as plt
# (et tout ton parsing jusqu’à la création de df_total et df_scene)
Le premier graphique illustre la quantité totale de mots prononcés par chaque personnage dans l’ensemble de la pièce.
On observe que Harpagon domine nettement la parole, suivi de Cléante et de Frosine.
Cette hiérarchie reflète déjà une logique dramatique : Harpagon, figure de l’avarice incarnée, occupe l’espace verbal comme il occupe l’espace matériel.
plt.imshow(plt.imread("avare_top_orateurs.png"))
plt.axis("off")
plt.show()
Le graphique suivant montre, pour chaque scène, la proportion de mots prononcés par les personnages principaux.
Cette visualisation permet de détecter les bascules de tension : certaines scènes sont dominées par Frosine, d’autres par Cléante ou Élise, révélant la mécanique d’équilibre typique de Molière.
On perçoit aussi une alternance rythmique : la parole circule comme un bien disputé — signe que, chez Molière, le langage lui-même devient monnaie d’échange.
plt.imshow(plt.imread("avare_par_scene.png"))
plt.axis("off")
plt.show()
L’analyse computationnelle des dialogues de L’Avare révèle un ordre latent : celui de la parole comme capital symbolique. Plus un personnage parle, plus il contrôle la scène ; mais certains, comme Frosine, dominent sans posséder le pouvoir matériel, tandis que d’autres, comme Élise, sont souvent présents par le silence. Ce contraste entre parole et pouvoir forme la véritable tension du texte.
Ainsi, derrière l’économie de l’argent se joue une économie du verbe — où parler, c’est dépenser, et se taire, c’est accumuler.