借助linxuanchen的一篇文檔《C#實現整型數據字任意編碼任意進制的轉換和逆轉換》,實現了使用62進制字符串壓縮16進制字符串的功能。主要是在原作者的基礎上做了一些轉換處理,總結思路如下:
1.16進制字符串(0-9A-F)轉換成Int64的整數,如:(hex16)DAFDE = (hex10)896734
2. 將Int64整數轉換為62進制數(0~9a-zA-Z):3LlA。(linxuanchen的代碼已經實現)
需要注意的幾個問題:
1.Int64最大的數值為Int64.MaxValue,該常數的值為 9,223,372,036,854,775,807;即十六進制的 0x7FFFFFFFFFFFFFFF。所以實際做字符串壓縮的時候,需要對16進制字符串長度進行處理,最多一次壓縮15個字符,避免溢出。
2.輸出的62進制字符串之間需要用分割符,否則無法解碼。
直接代碼如下:
using System;
using System.Collections.Generic;
//using System.Linq;
using System.Text;
// @ http://www.cnblogs.com/linxuanchen/archive/2012/02/02/2336099.html
// @ shadu {AT} foxmail.com
namespace HexCover
{
public class MyString
{
/// <summary>
/// 以MaxLength長度分割strHex16字符串
/// </summary>
/// <param name="strHex16"></param>
/// <param name="MaxLength"></param>
/// <returns></returns>
public static List<string> SplitHex16StingWithLength(string strHex16, int MaxLength)
{
string tmpStr = "";
List<string> StringList = new List<string>();
int count = strHex16.Length / MaxLength;
if (strHex16.Length % MaxLength != 0)
{
for (int i = 0; i <= count; i++)
{
if ((strHex16.Length - i * MaxLength) > MaxLength)
{
tmpStr = strHex16.Substring(i * MaxLength, MaxLength);
StringList.Add(tmpStr);
}
else
{
tmpStr = strHex16.Substring(i * MaxLength, (strHex16.Length % MaxLength));
StringList.Add(tmpStr);
}
}
}
else
{
for (int i = 0; i < count; i++)
{
tmpStr = strHex16.Substring(i * MaxLength, MaxLength);
StringList.Add(tmpStr);
}
}
return StringList;
}
}
public class Number
{
public string Characters
{
get;
set;
}
public int Length
{
get
{
if (Characters != null)
return Characters.Length;
else
return 0;
}
}
public Number()
{
Characters = "0123456789";
}
public Number(string characters)
{
Characters = characters;
}
/// <summary>
/// 數字轉換為指定的進制形式字符串
/// </summary>
/// <param name="number"></param>
/// <returns></returns>
public string ToString(long number)
{
List<string> result = new List<string>();
long t = number;
while (t > 0)
{
var mod = t % Length;
t = Math.Abs(t / Length);
var character = Characters[Convert.ToInt32(mod)].ToString();
result.Insert(0, character);
}
return string.Join("", result.ToArray());
}
/// <summary>
/// 指定字符串轉換為指定進制的數字形式
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public long FromString(string str)
{
long result = 0;
int j = 0;
char[] arr = str.ToCharArray();
Array.Reverse(arr);
//return new string(arr);
foreach (char ch in new string(arr))
//foreach (var ch in new string(str.ToCharArray().Reverse().ToArray()))
{
//Characters.Contains(
if (Characters.Contains(ch.ToString()))
{
result += Characters.IndexOf(ch) * ((long)Math.Pow(Length, j));
j++;
}
}
return result;
}
}
class Program
{
static void Print(long number, Number adapter)
{
Console.WriteLine("輸入數字:{0}", number);
Console.WriteLine("規則:{0}\t\t進制:{1}進制", adapter.Characters, adapter.Length);
var numtostr = adapter.ToString(number);
Console.WriteLine("轉換結果:{0}", numtostr);
var strtonum = adapter.FromString(numtostr);
Console.WriteLine("逆向轉換結果:{0}", strtonum);
Console.WriteLine();
Console.WriteLine("============ 無聊的分割線 ============");
Console.WriteLine();
}
static void Main(string[] args)
{
//傳統的2進制
Number n1 = new Number("01");
//傳統的8進制
Number n2 = new Number("01234567");
//傳統的16進制
Number n3 = new Number("0123456789ABCDEF");
//自定義編碼的N進制,這個可以用來做驗證碼?
Number n4 = new Number("爹媽說名字太長躲在樹後面會被部落發現");
//山寨一個短網址
Number n5 = new Number("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
Print(65535, n1);
Print(65535, n2);
Print(65535, n3);
Print(65535, n4);
Print(72057594037927934, n5);
Console.ReadKey();
//==== Added by Laien @ 2012-09-25
string strHex = "FFFFFFFFFFFFFFF3131CDAFDE";
string tmpStr = "" ;
List<string> strList = MyString.SplitHex16StingWithLength(strHex, 15);
foreach (string s in strList)
tmpStr += "-" + n5.ToString(Convert.ToInt64(s, 16));
Console.WriteLine("轉換前16進制字符串:{0}", strHex);
Console.WriteLine("轉換後62字符串:{0} (-是分隔符)", tmpStr);
Console.ReadKey();
}
}
}
運行結果如下