使用C ++进行行程解压缩

时间:2020-02-19 09:46:22

标签: c++ compression run-length-encoding

我有一个文本文件,其中包含我编码的字符串。

假设它是:aaahhhhiii kkkjjhh ikl wwwwwweeeett

这是用于编码的代码,可以很好地工作:

void Encode(std::string &inputstring, std::string &outputstring)
{
    for (int i = 0; i < inputstring.length(); i++) {
        int count = 1;
        while (inputstring[i] == inputstring[i+1]) {
            count++;
            i++;
        }
        if(count <= 1) {
            outputstring += inputstring[i];
        } else {
            outputstring += std::to_string(count);
            outputstring += inputstring[i];
        }
    }
}

输出符合预期:3a4h3i 3k2j2h ikl 6w4e2t

现在,我想将输出解压缩-回到原始状态。

而且从现在开始我一直在为此苦苦挣扎。

到目前为止我的想法:

void Decompress(std::string &compressed, std::string &original)
{
    char currentChar = 0;
    auto n = compressed.length();
    for(int i = 0; i < n; i++) {

        currentChar = compressed[i++];

        if(compressed[i] <= 1) {
            original += compressed[i];
        } else if (isalpha(currentChar)) {
            //
        } else {
            //
            int number = isnumber(currentChar).....
            original += number;
        }
    }
}

我知道我的Decompress函数似乎有点混乱,但是我对这个函数很迷失。 抱歉。

在stackoverflow上也许有人愿意帮助失落的初学者。

感谢您的帮助。

3 个答案:

答案 0 :(得分:2)

假设输入字符串不能包含数字(编码不能覆盖数字,例如,字符串"3a""aaa"都将导致编码后的字符串"3a" –您想要的方式再次分解?),则可以如下解压缩:

unsigned int num = 0;
for(auto c : compressed)
{
    if(std::isdigit(static_cast<unsigned char>(c)))
    {
        num = num * 10 + c - '0';
    }
    else
    {
        num += num == 0; // assume you haven't read a digit yet!
        while(num--)
        {
            original += c;
        }
    }
}

不过,未经测试的代码...

不过,字符串中的字符实际上只是数字值。您也可以将char(或signed charunsigned char)视为普通的8位整数。您也可以在这样的字节中存储数值。通常,您使用这种方式进行长度编码:最多计数255个相等字符,将计数存储在一个字节中,并将字符存储在另一个字节中。然后将一个"a"编码为0x01 0x61(后者是a的ASCII值),"aa"将得到0x02 0x61,依此类推。如果必须存储超过255个相等的字符,则可以存储两对:0xff 0x61, 0x07 0x61用于包含字符a的262倍的字符串...解码然后变得不重要:您成对读取字符,解释的第一个字节作为数字,第二个作为字符–琐碎。而且您也可以用这种方式很好地覆盖数字。

答案 1 :(得分:0)

#include "string"
#include "iostream"


void Encode(std::string& inputstring, std::string& outputstring)
{
    for (unsigned int i = 0; i < inputstring.length(); i++) {
        int count = 1;
        while (inputstring[i] == inputstring[i + 1]) {
            count++;
            i++;
        }
        if (count <= 1) {
            outputstring += inputstring[i];
        }
        else {
            outputstring += std::to_string(count);
            outputstring += inputstring[i];
        }
    }
}

bool alpha_or_space(const char c)
{
    return isalpha(c) || c == ' ';
}

void Decompress(std::string& compressed, std::string& original)
{
    size_t i = 0;
    size_t repeat;
    while (i < compressed.length())
    {
        // normal alpha charachers
        while (alpha_or_space(compressed[i]))
            original.push_back(compressed[i++]);

        // repeat number
        repeat = 0;
        while (isdigit(compressed[i]))
            repeat = 10 * repeat + (compressed[i++] - '0');

        // unroll releat charachters
        auto char_to_unroll = compressed[i++];
        while (repeat--)
            original.push_back(char_to_unroll);
    }
}

int main()
{
    std::string deco, outp, inp = "aaahhhhiii kkkjjhh ikl wwwwwweeeett";

    Encode(inp, outp);
    Decompress(outp, deco);

    std::cout << inp << std::endl << outp << std::endl<< deco;

    return 0;
}

答案 2 :(得分:0)

解压缩可能无法以明确的方式进行,因为您没有定义前哨字符;也就是说,在给定压缩流的情况下,无法确定数字是原始单个数字还是代表重复的RLE命令。我建议使用“ 0”作为前哨字符。编码时,如果看到“ 0”,则仅输出010。其他任何char X都将转换为0NX,其中N是重复字节计数器。如果超过255,只需输出一个新的RLE重复命令