【求解】某字符集 散乱字符串的压缩算法

Italink 2019-11-22 05:57:31
是这样的,假如将形如"16ABDF1536F4080AB87DE"(十六进制字符集)这样的字符进行压缩,考虑按位存储,比如16进制字符就是:一个字节的高四位,低四位,分别存储一个字符,理论上可以将字符长度折半。主要是初次接触这样的算法,想请问一下论坛的各位老铁是否有压缩效率更高的算法。
起因只是想通过字符代码,来替换存储文件数据。不知道大家有没有玩过炉石传说,它可以通过二几个长度的字符串中读取30张卡的编号(牌库上千张卡),我也想做一个这样的字符串代码,用于数据交换
...全文
135 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
Italink 2019-11-24
  • 打赏
  • 举报
回复
引用 2 楼 这是一个正经昵称 的回复:
炉石的牌组代码只是base64 。或许你也可以用这个啊
测试文件 写完之后试了一下,的确是空间能压缩一半,长度甚至更多(有-ASCII值,被当成宽字符),但是就是有些不可见字符,看上去特别杂乱,我的目的其实只是将字符串的显示长度减少。我再构建个utf-8的压缩字典,应该就可以了 头文件

#ifndef	COMPRESS_STRING_H
#define COMPRESS_STRING_H
#include <string>
#include <map>
#include <iostream>
using namespace std;
class CompressedString {
private:
	map<char,int> characterSet;		//构建字符字典
	int bitSize;					//压缩单个字符后所占二进制位
public:
	CompressedString(string);			//通过字符集构造
	string compress(const string& str);		//压缩字符串
	string uncompress(const string& cp);	//解压缩
	void setCharacterSet(const string& s);	//设置字符集
	void display(const string& s);			//输出对比
};
#endif // COMPRESS_STRING_H
源文件

#include "CompressedString.h"
CompressedString::CompressedString(string s){
	setCharacterSet(s);
}
string CompressedString::compress(const string& raw)
{
	string cps(round(raw.size() * (double)bitSize / 8) + 1, ' ');
	char ch = 0;
	int index = 0;
	int pos = 0;
	for (int i = 0; i < raw.size(); i++) {
		for (int j = 0; j <bitSize; j++) {
			ch |= ((characterSet.at(raw[i])>>j) & 1)<<(index++);
			if (index == 8) {
				cps[pos++]=(ch);
				index = ch = 0;
			}
		}
	}
	if (index != 0) 		//当有剩余bit时
		cps[pos++] = (ch);
	cps[pos++] = index ? 8 - index : 8;	//记录末尾bit
	return cps;
}

string CompressedString::uncompress(const string& cp)
{
	string uncp(((cp.size()-1)*8-(8-cp.back()))/bitSize,' ');
	int index = 0;
	int pos = 0;
	for (int i = 0; i < cp.size()-1;) {
		int c = 0;
		for (int j = 0; j < bitSize; j++) {
			c |= (((cp[i] >> index++) & 1) << j);
			if (index == 8) {
				i++;
				if (i >= cp.size()-1)
					break;
				index = 0;
			}
		}
		if(pos<uncp.size())
			uncp[pos++]=((next(characterSet.begin(), c))->first);
	}
	return uncp;
}
void CompressedString::setCharacterSet(const string& s)
{
	for (int i = 0; i < s.size(); i++) 
		characterSet.insert({ s[i],i });
	bitSize = ceil(log2(s.size()));
}

void CompressedString::display(const string& s)
{
	cout << "原始字符串:" << s << "\t压缩字符串:[" << compress(s) << "]\t解压缩字符串:[" << uncompress(compress(s)) << "]" << endl;
}


#include <iostream>
#include "CompressedString.h"
#include <string>
using namespace std;
int main() {
	CompressedString s("0123456789ABCDEF");
	s.display("123456789");
	s.display("123445635464564532546ADCFEA");
	wstring str = L"123456" ;
	return 0;
}
  • 打赏
  • 举报
回复
炉石的牌组代码只是base64 。或许你也可以用这个啊
铖邑 2019-11-22
  • 打赏
  • 举报
回复
二十几个字节想表示出30个几千以内的整数,是不好压缩的,因为压缩空间很有限,并且很多压缩算法是通过字典来实现的,这个字典可能都要超过30了

5,530

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 模式及实现
社区管理员
  • 模式及实现社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧