82 lines
3.4 KiB
Python

#
# Sam Hadow - Huffman-py
# Copyright (C) 2023
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import re
def huffman_decode(encodedData, noeud_actuel):
racine = noeud_actuel
decodedOutput = []
# cas particulier, si on a qu'un seul sommet dans l'arbre (lettre unique dans le texte d'origine)
if (not racine.left and not racine.right):
string = ''.join([racine.lettres for _ in encodedData])
return string
# cas normal
for x in encodedData:
if x == '1':
noeud_actuel = noeud_actuel.right
elif x == '0':
noeud_actuel = noeud_actuel.left
# On regarde si on est encore dans les noeuds internes, sinon (pour une feuille) on peut décoder une lettre.
try:
# noeud interne
if noeud_actuel.left.lettres == None and noeud_actuel.right.lettres == None:
pass
except AttributeError:
# feuille
decodedOutput.append(noeud_actuel.lettres)
noeud_actuel = racine
if noeud_actuel != racine and (noeud_actuel.right !=None or noeud_actuel.left != None):
# si on finit dans un noeud interne c'est que l'arbre ne correspondait pas au texte encodé.
raise ValueError ("L'arbre ne correspond pas en texte encodé.")
string = ''.join([str(item) for item in decodedOutput])
return string
def decode_from_dico(encodedData, dico):
# on suppose le dico en entrée de la forme {lettre:binaire} (le même que celui affiché dans la console par l'encodage)
# on inverse d'abord les paires key:value (les lettres seront uniques comme les codes)
dico = {value:key for key,value in dico.items()}
texte = str(encodedData)
# on regarde si on a bien un texte en binaire en entrée
char_invalide = re.compile('[^01]')
if char_invalide.search(texte):
raise TypeError ('Le texte en entrée doit être en binaire.')
decoded = ''
sorted_dict = dict(sorted(dico.items(), key=lambda x: len(x[0]), reverse=False))
while len(texte) > 0:
for i,binaire in enumerate(sorted_dict.keys()):
if binaire == texte[0:len(binaire)]:
# on décode si on trouve la portion du texte codé dans nos codes
decoded += sorted_dict[binaire]
# on supprime la partie qui vient d'être décodée
texte = texte[len(binaire):]
# on passe à l'itération suivante du while
break
# si aucun code correspond après avoir parcouru le dictionnaire on lève une exception
elif i == len(sorted_dict.keys())-1:
raise ValueError ('Impossible de convertir le texte avec le dictionnaire fourni.')
return decoded