【问题标题】:String into binary字符串转换成二进制
【发布时间】:2022-01-20 08:57:35
【问题描述】:

我使用了我们编写的 Huffman 编码来压缩文件。 该函数采用String,其输出为String

问题是我想将它保存为二进制文件以获得小于原始大小的大小,但是当我将它(0 和 1)作为字符串取回时,它的大小大于主文件。如何将该字符串(0 和 1)转换为二进制,以便每个字符都保存在 1 位中?我正在使用 Qt 来实现这一点:

string Huffman_encoding(string text)
{
    buildHuffmanTree(text);

    string encoded = "";
    unordered_map<char, string> StringEncoded;
    encoding(main_root, "", StringEncoded);

    for (char ch : text) {
        encoded += StringEncoded[ch];
    }
    return encoded;
}

【问题讨论】:

  • 这能回答你的问题吗? How to read/write arbitrary bits in C/C++
  • 这没有足够的代码来帮助你。霍夫曼代码不适合字节(例如,它们可以是 3 位或 5 位)。所以你需要一种比特流,然后将该比特流写入文件。

标签: c++ qt


【解决方案1】:

规范的解决方案使用“位打包器”,它接受位串并发出打包字节。首先,将encoded 替换为以下实例:

class BitPacker {
  QByteArray res;
  quint8 bitsLeft = 8;
  quint8 buf = 0;

  public:
  void operator+=(const std::string& s) {
    for (auto c : s) {
      buf = buf << 1 | c - '0';
      if (--bitsLeft == 0) {
        res.append(buf);
        buf = 0;
        bitsLeft = 8;
      }
    }
  }

  QByteArray finish() {
    if (bitsLeft < 8) {
      res.append(buf << bitsLeft);
      buf = 0;
      bitsLeft = 8;
    }
    return res;
  }
}

operator+= 将向buf 添加额外的位并将完整字节刷新到res。在该过程结束时,您可能会留下 3 位。 finish 使用一种简单的算法:它用零填充缓冲区以生成最终字节并将完全编码的缓冲区交还给您。

更复杂的解决方案可能是引入源字符集中不存在的显式“流结束”标记。

【讨论】:

    【解决方案2】:

    似乎您正在搜索的是一种将包含 0 和 1 序列(如“0000010010000000”)的字符串转换为实际二进制表示(本例中为数字 4 和 128)的方法。

    这可以通过这样的函数来实现:

    #include <iostream>
    #include <string>
    
    #include <cstdint>
    #include <vector>
    
    std::vector<uint8_t> toBinary(std::string const& binStr)
    {
        std::vector<uint8_t> result;
        result.reserve(binStr.size() / 8);
        size_t pos = 0;
        size_t len = binStr.length();
        while (pos < len)
        {
             size_t curLen = std::min(static_cast<size_t>(8), len-pos);
             auto curStr = binStr.substr(pos, curLen) + std::string(8-curLen, '0');
             std::cout << "curLen: " << curLen << ", curStr: " << curStr << "\n";
             result.push_back(std::stoi(curStr, 0, 2));
             pos += 8;
        }
        return result;
    }
    
    // test:
    int main()
    {
      std::string binStr("000001001000000001");
      auto bin = toBinary(binStr);
      for (auto i: bin)
      {
        std::cout << static_cast<int>(i) << "  ";
      }
      return 0;
    }
    

    输出:

    4 128 64
    

    然后您可以对这些数字做任何您想做的事情,例如将它们写入二进制文件。

    请注意,toBinary 如上所述,如果不完整,则用零填充最后一个字节。

    【讨论】:

    • @AnoopRana 早一点按下提交按钮 ;)。希望现在一切都好?
    • 是的,现在看起来不错。
    • 感谢您的帮助,但我不想这样做,我希望它们仍然是 0.1,但是当我将它们保存在文件中时,它们将保存为 0 的 1,而不是 0 和 1 的字符串,因为字符串字符占用 8 位,而我想将其保存为二进制仅占用 1 位
    • 不确定我理解你的意思 - 你想将包含“0”和“1”字符的字符串(我们称之为位字符串)转换为实际的二进制数据,对吗?这就是我的功能正在做的事情。我在这里转换成的数字格式占用的内存比“位串”少 8 倍。在计算机中一切都是二进制的——即使是字符串也是以位存储的;所以当你“仍然希望它们为 0.1”时,我不知道你的意思。在计算机中,两种表示最终都存储为 0 和 1...
    • 我用过,但你知道如何使用 qt 将它保存到文件中吗? ,谢谢帮助
    【解决方案3】:

    您可以像这样使用按位逻辑创建比特流:

    #include <cassert>
    #include <string>
    #include <stdexcept>
    #include <vector>
    
    
    auto to_bit_stream(const std::string& bytes)
    {
        std::vector<std::uint8_t> stream;
        std::uint8_t shift{ 0 };
        std::uint8_t out{ 0 };
    
        // allocate enough bytes to hold the bits
        // speeds up the code a bit
        stream.reserve((bytes.size() + 7) / 8);
    
        // loop over all bytes
        for (const auto c : bytes)
        {
            // check input
            if (!((c == '0') || (c == '1'))) throw std::invalid_argument("invalid character in input");
    
            // shift output by one to accept next bit
            out <<= 1;
    
            // keep track of number of shifts
            // after 8 shifts a byte has been filled
            shift++;
    
            // or the output with a 1 if needed
            out |= (c == '1');
    
            // complete an output byte
            if (shift == 8)
            {
                stream.push_back(out);
                out = 0;
                shift = 0;
            }
        }
    
        return stream;
    }
    
    
    int main() 
    {
        // stream is 8 bits per value, values 0,1,2,3
        auto stream = to_bit_stream("00000000000000010000001000000011");
    
        assert(stream.size() == 4ul);
        assert(stream[0] == 0);
        assert(stream[1] == 1);
        assert(stream[2] == 2);
        assert(stream[3] == 3);
            
        return 0;
    }
    

    【讨论】:

      【解决方案4】:

      使用 std::stoi()

      int n = std::stoi("01000100", nullptr, 2);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-02-24
        • 1970-01-01
        • 2014-08-02
        • 2019-08-23
        • 1970-01-01
        相关资源
        最近更新 更多