字符串转二进制
String into binary
我使用了我们编写的霍夫曼编码来压缩文件。
该函数采用 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;
}
您要搜索的似乎是一种将包含 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
如上所述,如果最后一个字节不完整,则用零填充。
规范解决方案使用接受位串并发出打包字节的“位打包器”。首先,将 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
使用一个简单的算法:它用零填充缓冲区以产生最后一个字节,然后将完全编码的缓冲区返回给您。
更复杂的解决方案可能是引入源字符集中不存在的显式“流结束”标记。
您可以像这样使用按位逻辑创建比特流:
#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;
}
使用std::stoi()
int n = std::stoi("01000100", nullptr, 2);
我使用了我们编写的霍夫曼编码来压缩文件。
该函数采用 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;
}
您要搜索的似乎是一种将包含 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
如上所述,如果最后一个字节不完整,则用零填充。
规范解决方案使用接受位串并发出打包字节的“位打包器”。首先,将 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
使用一个简单的算法:它用零填充缓冲区以产生最后一个字节,然后将完全编码的缓冲区返回给您。
更复杂的解决方案可能是引入源字符集中不存在的显式“流结束”标记。
您可以像这样使用按位逻辑创建比特流:
#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;
}
使用std::stoi()
int n = std::stoi("01000100", nullptr, 2);