Exercice 1 — Évaluation de la force d'un mot de passe
Calculer le score et la force d'un mot de passe
| Bonus | Formule |
|---|---|
| Longueur totale | len(pwd) × 4 |
| Diversité majuscules | (len − nb_maj) × 2 |
| Diversité minuscules | (len − nb_min) × 3 |
| Caractères spéciaux | nb_non_alpha × 5 |
| Pénalité | Formule |
|---|---|
| Suite minuscules consécutives | longMin(pwd) × 2 |
| Suite majuscules consécutives | longMaj(pwd) × 3 |
Classification : score < 20 → Très faible | < 40 → Faible | < 80 → Fort | ≥ 80 → Très fort
Exemple de calcul — P@cSI_promo2017
| Statistique | Valeur | Contribution |
|---|---|---|
| Longueur totale | 15 | 15 × 4 = 60 |
| Diversité maj (P, S, I → 3) | 15 − 3 = 12 | 12 × 2 = 24 |
| Diversité min (c,p,r,o,m,o → 6) | 15 − 6 = 9 | 9 × 3 = 27 |
| Non-alphabétiques (@,_,2,0,1,7 → 6) | 6 | 6 × 5 = 30 |
| Total Bonus | 141 | |
| Pénalité min ('promo' → 5) | 5 | 5 × 2 = 10 |
| Pénalité maj ('SI' → 2) | 2 | 2 × 3 = 6 (≠ 4 dans l'exemple) |
| Total Pénalités | 16 | |
| Score final | 125 → Très fort | |
Travail demandé :
- NbCMin(pwd) — nombre de lettres minuscules
- NbCMaj(pwd) — nombre de lettres majuscules
- NbCAlpha(pwd) — nombre de caractères non alphabétiques
- LongMaj(pwd) — longueur de la plus longue suite de majuscules
- LongMin(pwd) — longueur de la plus longue suite de minuscules
- Score(pwd) — afficher le score et la force du mot de passe
longMaj et longMin utilisent des comparaisons strictes ('A' < c < 'Z') au lieu de larges ('A' <= c <= 'Z').Conséquence : les lettres
'A', 'Z', 'a', 'z' ne sont pas comptabilisées dans les suites. De plus, la séquence courante s n'est jamais remise à zéro lors d'une rupture (oubli de s = 0).def NbcMin(passe):
"""Compte les lettres minuscules a–z."""
return sum(1 for c in passe if 'a' <= c <= 'z')
def NbcMaj(passe):
"""Compte les lettres majuscules A–Z."""
return sum(1 for c in passe if 'A' <= c <= 'Z')
def NbcAlpha(passe):
"""Compte les caractères non alphabétiques (chiffres, symboles…)."""
return len(passe) - NbcMaj(passe) - NbcMin(passe)
def longMaj(passe):
"""
Longueur de la plus longue séquence consécutive de majuscules.
Bug corrigé : comparaisons larges <= au lieu de strictes <
et remise à zéro de s après chaque rupture.
"""
d = s = 0
for c in passe:
if 'A' <= c <= 'Z': # inclut A et Z
s += 1
if s > d:
d = s
else:
s = 0 # remise à zéro à chaque rupture
return d
def longMin(passe):
"""Longueur de la plus longue séquence consécutive de minuscules."""
d = s = 0
for c in passe:
if 'a' <= c <= 'z':
s += 1
if s > d:
d = s
else:
s = 0
return d
def score(password):
"""Calcule et affiche le score de force du mot de passe."""
n = len(password)
maj = NbcMaj(password)
min_ = NbcMin(password)
spec = NbcAlpha(password)
bonus = n * 4 + (n - maj) * 2 + (n - min_) * 3 + spec * 5
penalites = longMaj(password) * 3 + longMin(password) * 2
val = bonus - penalites
print(f"Score : {val}")
if val < 20: print("Force : Très faible")
elif val < 40: print("Force : Faible")
elif val < 80: print("Force : Fort")
else: print("Force : Très fort")
# Tests
for pwd in ["abc", "P@cSI_promo2017", "Aa1!", "AAABBB", "p@ssW0rd!"]:
print(f"\n[{pwd}]")
score(pwd)import re
def analyser(pwd):
"""Retourne un dict avec toutes les statistiques du mot de passe."""
n = len(pwd)
maj = sum(c.isupper() for c in pwd)
min_ = sum(c.islower() for c in pwd)
spec = sum(not c.isalpha() for c in pwd)
# Plus longue séquence : re.findall trouve toutes les séquences,
# max(..., default=0) retourne la plus longue (0 si aucune)
long_maj = max((len(m) for m in re.findall(r'[A-Z]+', pwd)), default=0)
long_min = max((len(m) for m in re.findall(r'[a-z]+', pwd)), default=0)
return dict(n=n, maj=maj, min_=min_, spec=spec,
long_maj=long_maj, long_min=long_min)
def score(pwd):
"""Calcule le score et retourne (valeur, niveau)."""
s = analyser(pwd)
bonus = s['n']*4 + (s['n']-s['maj'])*2 + (s['n']-s['min_'])*3 + s['spec']*5
penalites = s['long_maj']*3 + s['long_min']*2
val = bonus - penalites
niveau = ("Très faible" if val < 20 else
"Faible" if val < 40 else
"Fort" if val < 80 else "Très fort")
return val, niveau
# Tests
mots_de_passe = [
"abc",
"Password1",
"P@cSI_promo2017",
"Tr0ub4dor&3",
"correct-horse-battery",
]
print(f"{'Mot de passe':<25} {'Score':>6} Niveau")
print("-" * 45)
for pwd in mots_de_passe:
val, niveau = score(pwd)
print(f"{pwd:<25} {val:>6} {niveau}")Mot de passe Score Niveau --------------------------------------------- abc 19 Très faible Password1 57 Fort P@cSI_promo2017 125 Très fort Tr0ub4dor&3 90 Très fort correct-horse-battery 76 Fort
re.findall(r'[A-Z]+', pwd) extrait toutes les suites de majuscules en une seule instruction. Combiner avec max(..., key=len) donne directement la plus longue, sans boucle explicite.P@cSI_promo2017
Score : 125 Force : Très fort
Exercice 2 — Décodeur Braille
Convertir un texte Braille en alphabet français
*) soit non saillant (-).Disposition des points :
| 1 | 4 |
| 2 | 5 |
| 3 | 6 |
Exemple :
H = **--*- (points 1, 2, 5 saillants)LETTRE code6Exemple :
A *-----, B **----Braille.txt : une ligne par mot, chaque mot = blocs de 6 caractères concaténés
Exemple : ligne
**----*-*-*- = B + O = "BO"Décodage de "BONJOUR"
| Lettre | Code Braille | Points saillants |
|---|---|---|
| B | **---- | 1, 2 |
| O | *-*-*- | 1, 3, 5 |
| N | *-***- | 1, 3, 4, 5 |
| J | -*-**- | 2, 4, 5 |
| U | *-*--* | 1, 3, 6 |
| R | ***-*- | 1, 2, 3, 5 |
Travail demandé :
Écrire un programme Python pour décoder le fichier Braille.txt et afficher le texte en alphabet français (un espace entre chaque mot).
nb = len(j) // 6 avec j (ligne brute avec \n), mais parcourt c = j.strip(). Si la ligne fait 42 caractères + \n = 43, alors 43 // 6 = 7 au lieu de 42 // 6 = 7 (coïncide ici, mais peut échouer). Il faut toujours calculer nb = len(c) // 6 après le strip(). De plus, le dictionnaire est construit avec l = c.split(' ') qui risque de produire des éléments vides si plusieurs espaces séparent la lettre du code.def dictionnaire(fichier):
"""
Construit le dict {code6: lettre} depuis Codes_braille.txt.
Correction : utiliser split() sans argument gère les espaces multiples.
"""
dic = {}
with open(fichier) as f:
for ligne in f:
parties = ligne.strip().split() # split() sans argument
if len(parties) == 2:
lettre, code = parties[0], parties[1]
dic[code] = lettre
return dic
def decoder_ligne(ligne, dic):
"""
Décode une ligne braille (un mot) en lettres.
Correction : len(c) après strip() et non len(j) sur la ligne brute.
"""
c = ligne.strip()
nb = len(c) // 6 # sur la chaîne nettoyée
mot = ""
for k in range(nb):
code = c[k*6 : k*6 + 6]
mot += dic.get(code, '?') # '?' si code inconnu
return mot
def decoder_fichier(braille_txt, codes_txt='codes_Braille.txt'):
"""Lit Braille.txt et retourne le texte décodé (mots séparés par espace)."""
dic = dictionnaire(codes_txt)
mots = []
with open(braille_txt) as f:
for ligne in f:
if ligne.strip(): # ignorer les lignes vides
mots.append(decoder_ligne(ligne, dic))
return ' '.join(mots)
print(decoder_fichier('braille.txt'))BONJOUR PSI
split(' ') découpe sur un espace exactement : si le fichier contient des tabulations ou des espaces multiples, la liste contiendra des chaînes vides.split() sans argument découpe sur tout espace blanc consécutif et ignore les séparateurs multiples → plus robuste pour lire des fichiers de données.**----*-*-*-*-***--*-**-*-*-*-*-*--****-*- ****---***---*-*--
BONJOUR PSI
Récapitulatif
| Exercice | Fonctions | Technique clé | Bugs corrigés |
|---|---|---|---|
| Force mot de passe | NbcMin, NbcMaj, NbcAlpha, longMin, longMaj, score | Comptage de caractères, suites consécutives, re.findall | Comparaisons < → <= dans longMaj/longMin ; remise à zéro de s |
| Décodeur Braille | dictionnaire, decoder_ligne, decoder_fichier | Dictionnaire inverse code→lettre, découpage en blocs de 6 | len(j)//6 → len(c)//6 ; split(' ') → split() |
- Toujours appliquer
.strip()avant de calculerlen()sur une ligne lue depuis un fichier (le\nfinal peut fausser le calcul). - Préférer
split()sans argument pour parser des fichiers de données : gère les espaces multiples et tabulations automatiquement. - Les comparaisons de caractères doivent être larges (
<=) pour inclure les bornes ('A', 'Z', 'a', 'z'). - Utiliser
with open(...)garantit la fermeture des fichiers même en cas d'exception. re.findall(r'[A-Z]+', s)est une façon élégante d'extraire toutes les séquences consécutives de majuscules sans boucle explicite.
Discussion (0)
Soyez le premier à laisser un commentaire !
Laisser un commentaire
Votre commentaire sera visible après modération.