將正整數數值轉換成任意進制編碼之方法
因為專案上有一個計量並縮短表述之需求,故需要將大型的整數轉換成某進制的編碼,因而寫下這篇文章記錄。其實人類習慣的十進制系統,說穿了就是用0-9這10種符號來進行代表,也就是說,我們可以創造一個隨意且不重複的符號序列,就可以達成編碼的需求,且符號數量長度(字元數)就恰好代表的進制的位數。舉例來說,利用我們常見的「0-9」+「a-z」的符號共36個字元,若將其應用在編碼上,就相當於是36進制系統了。若還是想不透的話請再想想16進制,其數據資訊表示字元不就是「0-9」+「a-f」嗎?
將數值轉換成任意進制(任意符號)類別
這個類別最主要的用意,就是將認知中的正整數數值,轉換成任意進制(任意符號)的編碼與解碼,在這邊輸入的正整數我們將採用C#裡面的ulong,也就是System.UInt64,其最大值MaxValue可達18446744073709551615,相當於18.4 * 1018,連中文我都不會唸了,我想是夠了。
不再採用更上去的Decimal型別是因為我本身覺得這樣的數字代表量非常夠了,再上去的數字也不是我想要處理與思考的重點,因此我將這個對轉的需求包裝成一個類別,程式碼如下:
public class BaseX
{ //定義編碼要使用的符號,多少符號字數就相當於多少進制,舉例來說「0-9|A-Z」,就是36進制
private const string _cSymbols = @"0123456789abcdefghijklmnopqrstuvwxyz";
private static char[] _arySymbols = _cSymbols.ToCharArray();
private static ulong _iLength = (ulong)_cSymbols.Length;
//顯示當前編碼字元數
public static int GetBaseNumber => (int)_iLength;
//顯示當前編碼套用在ulong.MaxValue,最大占用字元長度
public static int GetEncodeMaxLength => (int)System.Math.Ceiling(System.Math.Log(ulong.MaxValue) / System.Math.Log(_iLength));
/// <summary>
/// 將數值轉換成編碼
/// </summary>
/// <param name="iValue">數值</param>
/// <param name="bAutoPadding">是否自動補位</param>
/// <returns>編碼</returns>
public static string DecimalToBase(ulong iValue, bool bAutoPadding = false)
{
var cResult = new System.Text.StringBuilder();
if (iValue == 0)
{ cResult.Append("0"); }
while (iValue > 0)
{
var iPoint = iValue % _iLength;
cResult.Insert(0, _arySymbols[iPoint]);
iValue = iValue / _iLength;
}
return bAutoPadding switch
{
true => cResult.ToString().PadLeft(GetEncodeMaxLength, '0'),
_ => cResult.ToString(),
};
}
/// <summary>
/// 將編碼轉換成數值
/// </summary>
/// <param name="cValue">編碼</param>
/// <returns>數值</returns>
public static ulong BaseToDecimal(string cValue)
{
ulong iResult = 0;
var aryValue = cValue.ToCharArray();
for (int i = 0; i < aryValue.Length; i++)
{ iResult = (iResult * _iLength) + (ulong)_cSymbols.IndexOf(aryValue[i]); }
return iResult;
}
}
執行與結果
執行的範例程式碼如下:
var oRND = new System.Random();
ulong iValue = (ulong)oRND.NextInt64(0, long.MaxValue);
WriteLine($"當前編碼位元:BASE {BaseX.GetBaseNumber}");
WriteLine($"ulong MAX編碼後最大長度:{BaseX.GetEncodeMaxLength}");
WriteLine($"數值:{iValue}");
var cCode = BaseX.DecimalToBase(iValue, bAutoPadding:true);
WriteLine($"編碼:{cCode}");
WriteLine($"解碼:{BaseX.BaseToDecimal(cCode)}");
範例A:假設編碼符號是採用可在URL通行的BASE64編碼(0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_-),那麼結果會如下所示:
當前編碼位元:BASE 64
ulong MAX編碼後最大長度:11
數值:2714104429535159729
編碼:2mGrVB5MumN
解碼:2714104429535159729
範例B:假設編碼符號是採用常規認知,不區分大小寫字元的BASE36編碼(0123456789abcdefghijklmnopqrstuvwxyz),那麼結果會如下所示:
當前編碼位元:BASE 36
ulong MAX編碼後最大長度:13
數值:6002481443502488317
編碼:19lqu37e767lp
解碼:6002481443502488317
範例C:示範基於BASE36編碼與自動補位,那麼結果會如下所示:
當前編碼位元:BASE 36
ulong MAX編碼後最大長度:13
數值:99887766554433
編碼:0000zent16ibl
解碼:99887766554433
範例D:這次作法比較「中二」點,採用注音符號(ㄅㄆㄇㄈㄉㄊㄋㄌㄍㄎㄏㄐㄑㄒㄓㄔㄕㄖㄗㄘㄙㄚㄛㄜㄝㄞㄟㄠㄡㄢㄣㄤㄥㄦㄧㄨㄩ)37個字母進行火星文編碼,那麼結果會如下所示:
當前編碼位元:BASE 37
ulong MAX編碼後最大長度:13
數值:1114873564797214516
編碼:ㄋㄎㄤㄖㄚㄚㄖㄢㄡㄟㄤㄍ
解碼:1114873564797214516
最後還是要特別提醒一下,編碼不是密碼,就算你採用注音符號或是將字符打亂順序後再進行編碼,其實對現代電腦系統來說要反推算出規則簡直易如反掌,若想要套用到正式用途上強烈建議審慎評估!