65.9K
CodeProject 正在变化。 阅读更多。
Home

简单的字符串压缩算法

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.75/5 (15投票s)

2011 年 7 月 10 日

CPOL

4分钟阅读

viewsIcon

189461

downloadIcon

3706

一种高效的算法,用于将 7 位字符编码为 6 位或 5 位,以减小字符串大小

引言

数据压缩对于使用比原始表示形式更少的位数来编码信息总是很有用的。在许多应用中,信息的大小至关重要。在数据通信中,数据的大小也会影响成本。

该算法最初是为短信应用程序实现的。使用此算法,可以在相同的 7 位 GSM 网络中每条消息发送约 256 个字符(通常每条消息 160 个字符)。其思想是,该程序将标准的 7 位编码减少到某种特定于应用程序的 5 位编码系统,然后将其打包到字节数组中。当字符串很长时,此方法可以显着减小字符串的大小,并且压缩率不受字符串内容的影响。

算法

编码 

假设我们有一个包含 8 个字符的字符串(例如:“abcdefgh”)。如果将其放入字节数组,我们将得到一个大小为 8 的字节数组。下图显示了这些 ASCII 字符如何存储在数组中。

|97|98|99|100|101|102|103|104|

如果使用 ASCII 表示字符,则单个字符需要 8 位。一组 8 位可以表示 256 个不同的字符。但如果考虑当前应用程序,简单的短信可能只包含大约 26 个不同的字符。因此,有 5 位编码就足够了,它可以提供多达 32 个不同的字符来表示。为了转换为 5 位,让我们为上述字符分配新值。

| a = 1 | b=2 | c=3 | d=4 | e=5 | f=6 | g=7 | h=8 |

如果我们更仔细地查看新的字节数组,它看起来会像这样(字符的值以二进制表示)。

00000001|00000010|00000011|00000100|00000101|00000110|00000111|00001000|

但我们仍然使用 8 个字节来存储 8 个字符。在下一步中,我们将从左侧的第 3 位开始截断每个字节,并提取最低的 5 位。结果将如下所示:

|00001|00010|00011|00100|00101|00110|00111|01000|

我们可以像这样在字节数组中重新排列这些位:

|00001000|10000110|01000010|10011000|11101000|

现在我们将 8 个字节减少到 5 个字节。下一节将展示这 5 个字节如何转换为 8 个字节并获取原始信息。

解码

给定一个字节数组时,每个字节都应该被表示为二进制。然后,所有 1 和 0 将根据它们的索引排列,然后可以分割成 5 位一组。分割后,它将如下所示:

|00001  000|10  00011  0|0100  0010|1  00110  00|111  01000|

这些组可以转换为十进制,这些值代表我们编码的字符。

|00001  = 1(a)

000|10  = 2 (b) 

00011   = 3(c) 

0|0100 = 4 (d)

0010|1 = 5 (e)

00110  = 6 (f) 

00|111 = 7 (g) 

01000| = 8 (h)  

然后信息可以解码为“abcdefgh”。

Using the Code

class SixBitEnDec:负责编码和解码的类

变量

final static public int SIX_BIT = 6; 用于将操作标记为 6 位转换的常量

final static public int FIVE_BIT = 5; 用于将操作标记为 5 位转换的常量

函数

byte[] encode(String txt, int bit){
	int length = txt.length();
	float tmpRet1=0,tmpRet2=0;
	if(bit==6){
		tmpRet1=3.0f;
		tmpRet2=4.0f;
	}else if(bit==5){
		tmpRet1=5.0f;
		tmpRet2=8.0f;
	}
	byte encoded[]=new byte[(int)(tmpRet1*Math.ceil(length/tmpRet2))];
	char str[]=new char[length];
	txt.getChars(0,length,str,0);
	int chaVal = 0;
	String temp;
	String strBinary = new String("");
	for (int i = 0;i<length; i++){
		temp = Integer.toBinaryString(toValue(str[i]));
		while(temp.length()%bit != 0){
			temp="0"+temp;
		}
		strBinary=strBinary+temp;
	}
	while(strBinary.length()%8 != 0){
	   strBinary=strBinary+"0";
	}
	Integer tempInt =new Integer(0);
	for(int i=0 ; i<strBinary.length();i=i+8){
		tempInt = tempInt.valueOf(strBinary.substring(i,i+8),2);
		encoded[i/8]=tempInt.byteValue();
	}
	return encoded;
}

此函数负责整个编码操作。参数 txt 可以是包含英文字母字符的任何文本,而 bit 是要编码的位数。bit 的值可以是 5 或 6。此函数简单地从 toValue() 函数获取每个字符的相关值,然后获取每个值的二进制表示。然后,代码将所有这些二进制数字调整为 5 位或 6 位(根据 bit 的值)的长度,方法是截断最高有效位或在数字前面添加零。最后,将这些 1 和 0 排列成一个字符串,并将其分割成 8 位一组,以便存储在字节数组中。此函数将返回此字节数组作为编码后的字符串。

String decode(byte[] encoded, int bit){
	String strTemp = new String("");
	String strBinary = new String("");
	String strText = new String("");
	Integer tempInt =new Integer(0);
	int intTemp=0;
	for(int i = 0;i<encoded.length;i++){         
		if(encoded[i]<0){
			intTemp = (int)encoded[i]+256;
		}else
			intTemp = (int)encoded[i];
		strTemp = Integer.toBinaryString(intTemp);
		while(strTemp.length()%8 != 0){
			strTemp="0"+strTemp;
		}
		strBinary = strBinary+strTemp;
	}
	for(int i=0 ; i<strBinary.length();i=i+bit){
		tempInt = tempInt.valueOf(strBinary.substring(i,i+bit),2);
		strText = strText + toChar(tempInt.intValue()); 
	}
	return strText;
}

此函数负责整个解码操作。此函数将字节数组作为编码数据,并将 bit 用于将解码切换到 6 位或 5 位之一。在这里,数组中的值也被转换为二进制表示,然后转换为字符串。之后,它将根据 bit 的值分割成 5 位或 6 位一组。最后,从 toChar() 函数获取与该值相关的字符,并将其附加到字符串。该字符串将作为解码后的字符串从函数返回。

int toValue(char ch){
	int chaVal = 0;
	switch(ch){
		case' ':chaVal=0;break; case'a':chaVal=1;break;
		case'b':chaVal=2;break; case'c':chaVal=3;break;
		case'd':chaVal=4;break; case'e':chaVal=5;break;
		case'f':chaVal=6;break; case'g':chaVal=7;break;
		case'h':chaVal=8;break; case'i':chaVal=9;break;
		case'j':chaVal=10;break; case'k':chaVal=11;break;
		case'l':chaVal=12;break; case'm':chaVal=13;break;
		case'n':chaVal=14;break; case'o':chaVal=15;break;
		case'p':chaVal=16;break; case'q':chaVal=17;break;
		case'r':chaVal=18;break; case's':chaVal=19;break;
		case't':chaVal=20;break; case'u':chaVal=21;break;
		case'v':chaVal=22;break; case'w':chaVal=23;break;
		case'x':chaVal=24;break; case'y':chaVal=25;break;
		case'z':chaVal=26;break; case'.':chaVal=27;break;
		case'*':chaVal=28;break; case',':chaVal=29;break;
		case'\':chaVal=30;break; case'2':chaVal=31;break;
		case'A':chaVal=32;break; case'B':chaVal=33;break;
		case'C':chaVal=34;break; case'D':chaVal=35;break;
		case'E':chaVal=36;break; case'F':chaVal=37;break;
		case'G':chaVal=38;break; case'H':chaVal=39;break;
		case'I':chaVal=40;break; case'J':chaVal=41;break;
		case'K':chaVal=42;break; case'L':chaVal=43;break;
		case'M':chaVal=44;break; case'N':chaVal=45;break;
		case'O':chaVal=46;break; case'P':chaVal=47;break;
		case'Q':chaVal=48;break; case'R':chaVal=49;break;
		case'S':chaVal=50;break; case'T':chaVal=51;break;
		case'U':chaVal=52;break; case'V':chaVal=53;break;
		case'W':chaVal=54;break; case'0':chaVal=55;break;
		case'1':chaVal=56;break; case'3':chaVal=57;break;
		case'4':chaVal=58;break;case'5':chaVal=59;break;
		case'6':chaVal=60;break;case'7':chaVal=61;break;
		case'8':chaVal=62;break;case'9':chaVal=63;break;
		default:chaVal=0;
	}
	return chaVal;
}

此函数为给定字母表中的字符返回一个值。这些值小于 64,因此 6 位数字可以表示这些字符中的任何一个。

char toChar(int val){
	char ch = ' ';
	switch(val){
		case 0:ch=' ';break; case 1:ch='a';break;
		case 2:ch='b';break; case 3 :ch='c';break;
		case 4:ch='d';break; case 5 :ch='e';break;
		case 6:ch='f';break; case 7 :ch='g';break;
		case 8:ch='h';break; case 9 :ch='i';break;
		case 10:ch='j';break; case 11:ch='k';break;
		case 12:ch='l';break; case 13:ch='m';break;
		case 14:ch='n';break; case 15:ch='o';break;
		case 16:ch='p';break; case 17:ch='q';break;
		case 18:ch='r';break; case 19:ch='s';break;
		case 20:ch='t';break; case 21:ch='u';break;
		case 22:ch='v';break; case 23:ch='w';break;
		case 24:ch='x';break; case 25:ch='y';break;
		case 26:ch='z';break; case 27:ch='.';break;
		case 28:ch='*';break; case 29:ch=',';break;
		case 30:ch='\';break; case 31 :ch='2';break;
		case 32:ch='A';break; case 33:ch='B';break;
		case 34:ch='C';break; case 35:ch='D';break;
		case 36:ch='E';break; case 37:ch='F';break;
		case 38:ch='G';break; case 39:ch='H';break;
		case 40:ch='I';break; case 41:ch='J';break;
		case 42:ch='K';break; case 43:ch='L';break;
		case 44:ch='M';break; case 45:ch='N';break;
		case 46:ch='O';break; case 47:ch='P';break;
		case 48:ch='Q';break; case 49:ch='R';break;
		case 50:ch='S';break; case 51:ch='T';break;
		case 52:ch='U';break; case 53:ch='V';break;
		case 54:ch='W';break; case 55:ch='0';break;
		case 56:ch='1';break; case 57:ch='3';break;
		case 58:ch='4';break; case 59:ch='5';break;
		case 60:ch='6';break; case 61:ch='7';break;
		case 62:ch='8';break; case 63:ch='9';break;
		default:ch=' ';
	}
	return ch;
}

此函数返回与给定数字(在此代码中定义)相关的字符。分配给字符的数字并不重要,但每个数字都必须可以用 6 位表示。

如何使用

该程序演示了如何使用一个简单的界面来使用 SixBitEnDec 类。您可以插入一些文本并观察压缩后的文本大小以及解压缩后的文本。

© . All rights reserved.