最近我研究出来一种对字符串压缩的算法,虽然还有一定的缺陷。就是如果字符串中的字母过多的话,压缩效率会大大降低。这个算法主要是为压缩数字设计的。
现在把源码共享出来,希望大家多提意见。
using System;
namespace New919.Encrypt
{
/// <summary>
/// 改进之前的算法 , 对数字串采用四次截取压缩
/// </summary>
public class CompressStr
{
// 64进制字典
private static string[] strNumber = {"0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T",
"U","V","W","X","Y","Z","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z",
"-","/","(",")"};
private static string strStringInString = "";
private static string strNumberInString = "";
#region 压缩方法
#endregion
#region 转换为64进制方法
public static string Compress(string p_string)
{
// try
// {
char[] charArrFirst = Separate(p_string).ToCharArray();
#region 第一次截取
string strConnectFirst = "";
string strConnectSecond = "";
string strConnectThird = "";
string strConnectFourth = "";
for(int i = charArrFirst.Length - 1; i > -1 ; i --)
{
int intTemp = (int)charArrFirst[i];
if(strConnectFirst.Length == 16)
{
// 大于16就跳出循环
break;
}
else
{
// if(intTemp >= 48 && intTemp <= 57)
// {
strConnectFirst = Convert.ToString(charArrFirst[i]) + strConnectFirst;
// }
// else
// {
// break;
// }
}
}
// 第一次取数字串之后 , 整个字符串遗留下来的部分
string strAfterFirst = p_string.Substring(0 , p_string.Length - strConnectFirst.Length);
// 第一次截取完毕 , 成功分离数字段和字母段
#endregion
#region 第二次截取 , 在第一次截取的基础上 , 在 strAfterFirst 字符串的末尾寻找数字字符
// 首先判断第一次截取的数字串的长度是不是为16位 , 如果是的 , 字母段的末尾还可能存在数字字符 , 进一步的截取
if(strConnectFirst.Length == 16)
{
// 第二次截取的数字段
char[] charArrSecond = strAfterFirst.ToCharArray();
for(int i = charArrSecond.Length - 1 ; i > -1 ; i --)
{
int intTemp = (int)charArrSecond[i];
if(strConnectSecond.Length == 16)
{
break;
}
else
{
// if(intTemp >= 48 && intTemp <= 57)
// {
strConnectSecond = Convert.ToString(charArrFirst[i]) + strConnectSecond;
// }
// else
// {
// break;
// }
}
}
// 第二次截取数字串之后 , 整个字符串遗留下来的部分
// 第二次截取成功完成
}
string strAfterSecond = strAfterFirst.Substring(0 , strAfterFirst.Length - strConnectSecond.Length);
#endregion
#region 第三次截取
if(strConnectSecond.Length == 16)
{
char[] charArrThird = strAfterSecond.ToCharArray();
for(int i = charArrThird.Length - 1 ; i > -1 ; i --)
{
int intTemp = (int)charArrThird[i];
if(strConnectThird.Length == 16)
{
break;
}
else
{
// if(intTemp >= 48 && intTemp <= 57)
// {
strConnectThird = Convert.ToString(charArrThird[i]) + strConnectThird;
// }
// else
// {
// break;
// }
}
}
}
string strAfterThird = strAfterSecond.Substring(0 , strAfterSecond.Length - strConnectThird.Length);
#endregion
#region 第四次截取
if(strConnectThird.Length == 16)
{
char[] charArrFourth = strAfterThird.ToCharArray();
for(int i = charArrFourth.Length - 1 ; i > -1 ; i --)
{
int intTemp = (int)charArrFourth[i];
if(strConnectFourth.Length == 16)
{
break;
}
else
{
// if(intTemp >= 48 && intTemp <= 57)
// {
strConnectFourth = Convert.ToString(charArrFourth[i]) + strConnectFourth;
// }
}
}
}
// string strAfterFourth = strAfterThird.Substring(0 , strAfterThird.Length - strConnectThird.Length);
#endregion
// 压缩之后的
string strAfterCompressed = To64(strConnectFourth) + To64(strConnectThird) + To64(strConnectSecond) + To64(strConnectFirst);
return strAfterCompressed;
// }
// catch(Exception ex)
// {
// MessageBox.Show(ex.Message.ToString());
// return "ads";
// }
}
/// <summary>
/// 转换为64进制方法
/// </summary>
/// <param name="strSource">源字符串(数字形式的)</param>
/// <returns>转换之后的字符串(里面的表示符由数据字典中定义的)</returns>
private static string To64(string strSource)
{
if(strSource.Trim().Length != 0)
{
// 数据字典
long longNumber = Convert.ToInt64(strSource);
long longTemp;
int intOrder = 0;
// 存储转数制的时候得到的余数
long[] longCompressLeft = new long[1000000];
do
{
longTemp = longNumber;
longNumber = longTemp / 64;
longCompressLeft[intOrder++] = longTemp % 64;
}while(longNumber != 0);
string strCompress = "";
for(int i = intOrder - 1 ; i > -1 ; i -- )
{
strCompress += strNumber[longCompressLeft[i]];
}
return strCompress;
}
else
{
return "";
}
}
#endregion
#region 把64进制转换为10进制的方法
/// <summary>
/// 把64进制转换为10进制的方法
/// </summary>
/// <param name="strSource">待转换的字符串(必须是数字形式的)</param>
/// <returns>转换完之后的十进制数</returns>
private static string To10(string strSource)
{
if(strSource.Length != 0)
{
long longAfter = 0;
string strBuf;
for(int i = 0 ; i < strSource.Length ; i ++)
{
strBuf = strSource.Substring(i , 1);
for(int j = 0 ; j < 64 ; j ++)
{
if(strNumber[j] == strBuf)
{
longAfter += j * (Convert.ToInt64(Math.Pow(64 , strSource.Length - i - 1)));
}
}
}
return Convert.ToString(longAfter);
}
else
{
// 如果传进来的字符串为空 , 说明原字符串没有到达某个指定的长度位数 , 返回空
return "";
}
}
#endregion
#region 解压缩的方法
/// <summary>
/// 解压缩的方法
/// </summary>
/// <param name="p_string">待解压缩的字符串</param>
/// <returns>解压缩之后的原数字串</returns>
public static string UnCompress(string p_string)
{
string strInciseFirst = "";
string strInciseSecond = "";
string strInciseThird = "";
string strInciseFourth = "";
// string strInciseLast = "";
string strSource = p_string;
// 把压缩后字符串的最后9位得到
strInciseFirst = Incise(strSource);
// 得到除去最后9位之后的压缩字符串
// 成功截取
string strTempFirst = p_string.Substring(0 , p_string.Length - strInciseFirst.Length);
// 把上面的这个字符串再次的从最后面截取9位
// 成功截取
strInciseSecond = Incise(strTempFirst);
string strTempSecond = strTempFirst.Substring(0 , strTempFirst.Length - strInciseSecond.Length);
strInciseThird = Incise(strTempSecond);
string strTempThird = strTempSecond.Substring(0 , strTempSecond.Length - strInciseThird.Length);
strInciseFourth = Incise(strTempThird);
// if(strInciseFourth.Length == 9)
// {
// strInciseLast = strSource.Substring(0 , strSource.Length - strInciseFirst.Length - strInciseSecond.Length - strInciseThird.Length - strInciseFourth.Length);
// }
string strCompressedNumber = To10(strInciseFourth) + To10(strInciseThird) + To10(strInciseSecond) + To10(strInciseFirst);
return ConnectString(strCompressedNumber);
}
#endregion
#region 分割字符串方法
private static string Incise(string p_string)
{
char[] charArr = p_string.ToCharArray();
string strInciseFirst = "";
if(p_string.Length >= 9)
{
for(int i = p_string.Length -1 ; i > p_string.Length - 10 ; i --)
{
strInciseFirst = charArr[i] + strInciseFirst;
}
return strInciseFirst;
}
else
{
return p_string;
}
}
#endregion
#region 分离数字和字母
/// <summary>
/// 把待压缩串中的数字和字母分离,以便分别处理
/// </summary>
/// <param name="p_string"></param>
/// <returns></returns>
private static string Separate(string p_string)
{
string strSource = p_string;
char[] charArr = p_string.ToCharArray();
for(int i = 0 ; i < charArr.Length ; i ++)
{
// 这个时候是从字符串的左边开始向右边遍历的 , 之后还原也应该按照同样的顺序加进去
// 不然就错位了 , 解压缩会失败
if((int)charArr[i] >= 48 && (int)charArr[i] <= 58)
{
// 数字
strNumberInString = strNumberInString + charArr[i];
}
else
{
// 字母
// 字母加上该字母所在的位置(转换成64进制)
strStringInString = strStringInString + charArr[i] + To64(i.ToString());
}
}
// 把字符串中的数字串部分返回
return strNumberInString;
}
#endregion
/// <summary>
/// 把字母段和数字段连接起来
/// </summary>
/// <param name="p_strNumber">数字段</param>
/// <returns>解压缩之后的字符串</returns>
private static string ConnectString(string p_strNumber)
{
// 字母串
string strStringBeforeCompress = "";
// 单个字母在原字符串中的位置(的集合)
string strLetterOrder = "";
// 先分析字母段
if(strStringInString.Length != 0)
{
char[] charArrString = strStringInString.ToCharArray();
for(int i = 0 ; i < strStringInString.Length ; i ++)
{
if(i % 2 == 0)
{
// 字母段
// 字符串的索引从0开始,偶数位都是字母
strStringBeforeCompress = strStringBeforeCompress + charArrString[i];
}
else
{
// 位置段
// 奇数位都是它之前偶数位字符的位置段
strLetterOrder = strLetterOrder + charArrString[i];
}
}
// 执行完上面的这个过程 , 已经成功的把字母段和每个字母的位置分析出来了
// 之后的要做的只是按照每个字母的位置逐个把每个字母添加到解压缩时候的数字段中去 , 就完成了解压缩的过程
// 在上面的过程中 , 还不能把位置段的每个位置转换为10进制 , 因为转换之后就不知道是应该去一位数字还是两位 , 必须在连接的循环过程中转换为10进制 , 那时候每次都只取一个字符(作为位置),但是前提是每个字母在原字符串中的位置必须小于64
}
// 如果长度等于0 , 说明压缩之前的字符串中没有字母,是纯数字串 , 不需要执行下面的过程
if(strStringBeforeCompress.Length != 0)
{
char[] charArrLetter = strStringBeforeCompress.ToCharArray();
char[] charArrLetterOrder = strLetterOrder.ToCharArray();
int intOrder = 0;
do
{
}while(intOrder > charArrLetterOrder.Length);
}
return p_strNumber;
}
}
}