將正整數數值轉換成任意進制編碼之方法

因為專案上有一個計量並縮短表述之需求,故需要將大型的整數轉換成某進制的編碼,因而寫下這篇文章記錄。其實人類習慣的十進制系統,說穿了就是用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

最後還是要特別提醒一下,編碼不是密碼,就算你採用注音符號或是將字符打亂順序後再進行編碼,其實對現代電腦系統來說要反推算出規則簡直易如反掌,若想要套用到正式用途上強烈建議審慎評估!

C# Integer BigInteger ConvertTo EncodeTo BASE32 BASE36 BASE64 BaseAnyNumber