运行-长度解压使用C++

Run-length decompression using C++

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

假设是: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;
        }
    }
}

我知道我的解压缩功能看起来有点乱,但我对这个功能很迷惑。 抱歉。

也许 Whosebug 上有人愿意帮助迷路的初学者。

感谢您的帮助,我很感激。

#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;
}

假设输入字符串不能包含数字(这不能被你的编码覆盖,例如字符串 "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 倍的字符串......解码然后变得微不足道:你成对读取字符,你解释的第一个字节作为数字,第二个作为字符 - 休息是微不足道的。你也用这种方式很好地覆盖了数字。

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