Python LZ77 - алгоритм сжатия

#!/usr/bin/python3
# -*- coding: utf-8 -*-

# подключаемые модули

import math

# константы

tMethod = 'LZ77'
sizeSymbol = 8  # размер 1го символа в битах


# функции

def readInputText(fileName):
    tInput, nD, nB = '', 8, 5
    try:
        # пытаемся открыть файл на чтение
        f = open(fileName, 'rt', encoding='utf-8')
    except FileNotFoundError:
        # файл не найден - запрашиваем параметры с консоли
        tInput = input('\n введите исходное сообщение -').strip()
        try:
            nD = int(input('размер словаря (сим, default=8)-').strip())
        except ValueError:
            nD = 8
        try:
            nB = int(input('размер буфера (сим, default=5)-').strip())
        except ValueError:
            nB = 5
    else:
        # файл найден чтаем параметры из файла
        tInputLines = f.readlines()
        f.close()
        for tLine in tInputLines:
            if tLine[0:11] == 'tInputText=':
                tInput = tLine[11:].strip()
            elif tLine[0:6] == 'nDict=':
                try:
                    nD = int(tLine[6:].strip())
                except ValueError:
                    nD = 8
            elif tLine[0:6] == 'nBuff=':
                try:
                    nB = int(tLine[6:].strip())
                except ValueError:
                    nB = 8
    finally:
        # выводим параметры на консоль
        print('\n исхоное сообщение - {0}'.format(tInput))
        print('размер словаря - {0} сим.'.format(nD))
        print('размер буфера - {0} сим.'.format(nB))

        # сохраняем параметры в файл
        with open(fileName, 'wt', encoding='utf-8') as f:
            f.write('tInputText={0}\n'.format(tInput))
            f.write('nDict={0}\n'.format(nD))
            f.write('nBuff={0}\n'.format(nB))
    return tInput, nD, nB


# используем 36-ричную систему счисления для смещения и длины строки
def str36(num36):
    if (num36 >= 0) and (num36 <= 9):
        strNum = str(num36)
    elif (num36 >= 10) and (num36 <= 36):
        strNum = chr(0x0041 + num36 - 10)  # ord('A') = 0x0041
    else:
        strNum = 'Error'
    return strNum


def makeLZ77(d, ld, b, lb):
    i = d.find(b[0])
    # первый символ буфера в словаре не найден или это последний символ буфера
    if (i == -1) or (i == len(b) - 1):
        i = 0  # смещение
        n = 0  # длина подстроки
        Code = str36(i) + str36(n) + b[n]  # код lz77
    # первый символ буфера в словаре найден смещение - i
    else:
        n = 0  # длина подстроки
        while (n < len(d) - i) and (n < len(b)) and (b[n] == d[i + n]):
            # if n <= len(b):
            n += 1
            Code = str36(i) + str36(n) + b[n]  # код lz77
    sizeCode = ld + lb + sizeSymbol  # размер 1го lz77 кода в битах
    # сдвиг курсора код и размер кода
    return [n + 1, Code, sizeCode]


#####

def makeOutputText(fileName, tInput, nD, nB):
    print('\n' + 'метод {0}'.format(tMethod).center(max(nD, 7) + max(nB, 5) + 3 + 10))
    print('=={0}==={1}==={2}=='.format(''.ljust(max(nD, 7), '='), ''.ljust(max(nB, 5), '='), ''.ljust(3, '=')))
    print('| {0} | {1} | {2} |'.format('словарь'.center(max(nD, 7)), 'буфер'.center(max(nB, 5)), 'код'.center(3)))
    print('|-{0}-|-{1}-|-{2}-|'.format(''.ljust(max(nD, 7), '-'), ''.ljust(max(nB, 5), '-'), ''.ljust(3, '-')))
    f = open(fileName, 'wt', encoding='utf-8')
    f.write('метод {0}'.format(tMethod).center(max(nD, 7) + max(nB, 5) + 3 + 10) + '\n')
    f.write('=={0}==={1}==={2}==\n'.format(''.ljust(max(nD, 7), '='), ''.ljust(max(nB, 5), '='), ''.ljust(3, '=')))
    f.write('| {0} | {1} | {2} |\n'.format('словарь'.center(max(nD, 7)), 'буфер'.center(max(nB, 5)), 'код'.center(3)))
    f.write('|-{0}-|-{1}-|-{2}-|\n'.format(''.ljust(max(nD, 7), '-'), ''.ljust(max(nB, 5), '-'), ''.ljust(3, '-')))
    nInput = len(tInput)
    tOutput, sizeOutput = '', 0
    k = 0
    while k < nInput:
        if k < nD:  # определение содержимого словаря
            tDict = tInput[0:k]
        else:
            tDict = tInput[k - nD:k]
        tDict = tDict.rjust(nD, chr(0x02f3))
        # символ пустого месте также - 0x02da
        # определение содержимого буфера
        tBuff = tInput[k:k + nB]
        # получение сдвига курсора кода и его размера в битах
        if tMethod == 'LZ77':
            n, tCode, sizeCode = makeLZ77(tDict, math.ceil(math.log2(nD)), tBuff, math.ceil(math.log2(nB)))
        print('| {0} | {1} | {2} |'.format(tDict.ljust(max(nD, 7)), \
                                           tBuff.ljust(nB, chr(0x02da)).ljust(max(nB, 5)), tCode.ljust(3)))
        f.write('| {0} | {1} | {2} |'.format(tDict.ljust(max(nD, 7)), \
                                             tBuff.ljust(nB, chr(0x02da)).ljust(max(nB, 5)), tCode.ljust(3)))
        tOutput += tCode
        sizeOutput += sizeCode
        k += n
        # input()
    print('=={0}==={1}==={2}=='.format(''.ljust(max(nD, 7), '='), ''.ljust(max(nB, 5), '='), ''.ljust(3, '=')))
    f.write('=={0}==={1}==={2}==\n'.format(''.ljust(max(nD, 7), '='), ''.ljust(max(nB, 5), '='), ''.ljust(3, '=')))
    f.close()
    return tOutput, sizeOutput


def writeOutputText(fileName, tOutput, sizeOutput, nInput, nD):
    print('\n сжатое (по методу {0}) сообщение - {1}'.format(tMethod, tOutput))
    print('\n размер сжатого сообщения - {0} бит.'.format(sizeOutput))
    print('коэффициент сжатия - {0}.'.format(sizeOutput / (sizeSymbol * nInput)))

    with open(fileName, 'wt', encoding='utf-8') as f:
        f.write('tMethod={0}\n'.format(tMethod))
        f.write('tOutputText={0}\n'.format(tOutput))
        f.write('nDict={0}\n'.format(nD))
        f.write('\n размер сжатого сообщения - {} бит. \n'.format(sizeOutput))
        f.write('коэффициент сжатия - {0}.'.format(sizeOutput / (sizeSymbol * nInput)))
    return


# -*- Main -*-

# прочитаем исходное сообщение
tInputText, nDict, nBuff = readInputText('Lab2-1.txt')

# создадим сжатый текст
tOutputText, sizeOutputText = makeOutputText('Lab2-2.txt', tInputText, nDict, nBuff)

# сохраним сжатый текст
writeOutputText('Lab2-3.txt', tOutputText, sizeOutputText, len(tInputText), nDict)

Данный код - алгоритм сжатия LZ77. В процессе запуска с дефолтными значаниями (словарь = 8 и буфер = 5) при использовании входного слова (красная_краска) работает отлично, но если взять допустим (словарь = 8, буфер = 5 и вход.слово = красная_краска_красная_краска) то не работает, где то в конце, в методе str36 - ошибка. Не могли бы вы помочь с ее исправлением?

Вывод консоли


Ответы (0 шт):