UnicodeFormater.cs 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Globalization;
  4. using System.Linq;
  5. using System.Numerics;
  6. using System.Text;
  7. namespace Masuit.Tools.Strings;
  8. /// <summary>
  9. /// 数制格式化器
  10. /// </summary>
  11. public class UnicodeFormater
  12. {
  13. /// <summary>
  14. /// 数制表示字符集
  15. /// </summary>
  16. private List<string> Characters { get; }
  17. /// <summary>
  18. /// 进制长度
  19. /// </summary>
  20. public int Length => Characters.Count;
  21. /// <summary>
  22. /// 起始值偏移
  23. /// </summary>
  24. private readonly byte _offset;
  25. /// <summary>
  26. /// 数制格式化器
  27. /// </summary>
  28. public UnicodeFormater()
  29. {
  30. Characters = new List<string>() { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" };
  31. }
  32. /// <summary>
  33. /// 数制格式化器
  34. /// </summary>
  35. /// <param name="characters">符号集</param>
  36. /// <param name="offset">起始值偏移</param>
  37. public UnicodeFormater(string characters, byte offset = 0)
  38. {
  39. if (string.IsNullOrEmpty(characters))
  40. {
  41. throw new ArgumentException("符号集不能为空");
  42. }
  43. var enumerator = StringInfo.GetTextElementEnumerator(characters);
  44. Characters = new List<string>();
  45. while (enumerator.MoveNext())
  46. {
  47. Characters.Add(enumerator.GetTextElement());
  48. }
  49. _offset = offset;
  50. }
  51. /// <summary>
  52. /// 数制格式化器
  53. /// </summary>
  54. /// <param name="characters">符号集</param>
  55. /// <param name="offset">起始值偏移</param>
  56. public UnicodeFormater(List<string> characters, byte offset = 0)
  57. {
  58. if (characters.IsNullOrEmpty())
  59. {
  60. throw new ArgumentException("符号集不能为空");
  61. }
  62. Characters = characters;
  63. _offset = offset;
  64. }
  65. #if NET5_0_OR_GREATER
  66. /// <summary>
  67. /// 数制格式化器
  68. /// </summary>
  69. /// <param name="characters">符号集</param>
  70. /// <param name="offset">起始值偏移</param>
  71. public UnicodeFormater(ReadOnlySpan<byte> characters, byte offset = 0)
  72. {
  73. if (characters == null || characters.Length == 0)
  74. {
  75. throw new ArgumentException("符号集不能为空");
  76. }
  77. Characters = Encoding.UTF8.GetString(characters).Select(c => c.ToString()).ToList();
  78. _offset = offset;
  79. }
  80. /// <summary>
  81. /// 数制格式化器
  82. /// </summary>
  83. /// <param name="characters">符号集</param>
  84. /// <param name="offset">起始值偏移</param>
  85. public UnicodeFormater(ReadOnlySpan<char> characters, byte offset = 0)
  86. {
  87. if (characters == null || characters.Length == 0)
  88. {
  89. throw new ArgumentException("符号集不能为空");
  90. }
  91. Characters = characters.ToString().Select(c => c.ToString()).ToList();
  92. _offset = offset;
  93. }
  94. #endif
  95. /// <summary>
  96. /// 数制格式化器
  97. /// </summary>
  98. /// <param name="characters">符号集</param>
  99. /// <param name="offset">起始值偏移</param>
  100. public UnicodeFormater(byte[] characters, byte offset = 0)
  101. {
  102. if (characters == null || characters.Length == 0)
  103. {
  104. throw new ArgumentException("符号集不能为空");
  105. }
  106. Characters = Encoding.UTF8.GetString(characters).Select(c => c.ToString()).ToList();
  107. _offset = offset;
  108. }
  109. /// <summary>
  110. /// 数制格式化器
  111. /// </summary>
  112. /// <param name="characters">符号集</param>
  113. /// <param name="offset">起始值偏移</param>
  114. public UnicodeFormater(char[] characters, byte offset = 0)
  115. {
  116. if (characters == null || characters.Length == 0)
  117. {
  118. throw new ArgumentException("符号集不能为空");
  119. }
  120. Characters = characters.Select(c => c.ToString()).ToList();
  121. _offset = offset;
  122. }
  123. /// <summary>
  124. /// 数制格式化器
  125. /// </summary>
  126. /// <param name="base">进制</param>
  127. /// <param name="offset">起始值偏移</param>
  128. public UnicodeFormater(byte @base, byte offset = 0)
  129. {
  130. Characters = @base switch
  131. {
  132. <= 2 => new List<string>() { "0", "1" },
  133. > 2 and < 65 => "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/".Substring(0, @base).Select(c => c.ToString()).ToList(),
  134. >= 65 and <= 91 => "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%&()*+,-.:;<=>?@[]^_`{|}~\"".Substring(0, @base).Select(c => c.ToString()).ToList(),
  135. _ => throw new ArgumentException("默认进制最大支持91进制")
  136. };
  137. if (offset >= @base)
  138. {
  139. throw new ArgumentException("偏移量不能超过进制基数" + @base);
  140. }
  141. _offset = offset;
  142. }
  143. /// <summary>
  144. /// 数字转换为指定的进制形式字符串
  145. /// </summary>
  146. /// <param name="number"></param>
  147. /// <returns></returns>
  148. public string ToString(long number)
  149. {
  150. int start = 0;
  151. int resultOffset = 0;
  152. if (_offset > 0)
  153. {
  154. start = 1;
  155. resultOffset = _offset - 1;
  156. }
  157. number -= resultOffset;
  158. List<string> result = [];
  159. long t = Math.Abs(number);
  160. while (t != 0)
  161. {
  162. var mod = t % Length;
  163. t = Math.Abs(t / Length);
  164. var character = Characters[Convert.ToInt32(mod) - start];
  165. result.Insert(0, character);
  166. }
  167. if (number < 0)
  168. {
  169. result.Insert(0, "-");
  170. }
  171. return string.Join("", result);
  172. }
  173. /// <summary>
  174. /// 数字转换为指定的进制形式字符串
  175. /// </summary>
  176. /// <param name="number"></param>
  177. /// <returns></returns>
  178. public string ToString(BigInteger number)
  179. {
  180. int start = 0;
  181. int resultOffset = 0;
  182. if (_offset > 0)
  183. {
  184. start = 1;
  185. resultOffset = _offset - 1;
  186. }
  187. number -= resultOffset;
  188. List<string> result = [];
  189. if (number < 0)
  190. {
  191. number = -number;
  192. result.Add("0");
  193. }
  194. BigInteger t = number;
  195. while (t != 0)
  196. {
  197. var mod = t % Length;
  198. t = BigInteger.Abs(BigInteger.Divide(t, Length));
  199. var character = Characters[(int)mod - start];
  200. result.Insert(0, character);
  201. }
  202. return string.Join("", result);
  203. }
  204. /// <summary>
  205. /// 指定字符串转换为指定进制的数字形式
  206. /// </summary>
  207. /// <param name="str"></param>
  208. /// <returns></returns>
  209. public long FromString(string str)
  210. {
  211. byte start = 0;
  212. int resultOffset = 0;
  213. if (_offset > 0)
  214. {
  215. start = 1;
  216. resultOffset = _offset - 1;
  217. }
  218. int j = 0;
  219. var emoji = new List<string>();
  220. var enumerator = StringInfo.GetTextElementEnumerator(str);
  221. while (enumerator.MoveNext())
  222. {
  223. emoji.Add(enumerator.GetTextElement());
  224. }
  225. emoji.Reverse();
  226. return emoji.Where(Characters.Contains).Sum(ch => (Characters.IndexOf(ch) + start) * (long)Math.Pow(Length, j++)) + resultOffset;
  227. }
  228. /// <summary>
  229. /// 指定字符串转换为指定进制的大数形式
  230. /// </summary>
  231. /// <param name="str"></param>
  232. /// <returns></returns>
  233. public BigInteger FromStringBig(string str)
  234. {
  235. byte start = 0;
  236. int resultOffset = 0;
  237. if (_offset > 0)
  238. {
  239. start = 1;
  240. resultOffset = _offset - 1;
  241. }
  242. int j = 0;
  243. var emoji = new List<string>();
  244. var enumerator = StringInfo.GetTextElementEnumerator(str);
  245. while (enumerator.MoveNext())
  246. {
  247. emoji.Add(enumerator.GetTextElement());
  248. }
  249. emoji.Reverse();
  250. return emoji.Where(Characters.Contains).Aggregate(BigInteger.Zero, (current, c) => current + (Characters.IndexOf(c) + start) * BigInteger.Pow(Length, j++)) + resultOffset;
  251. }
  252. /// <summary>Returns a string that represents the current object.</summary>
  253. /// <returns>A string that represents the current object.</returns>
  254. public override string ToString()
  255. {
  256. return Length + "进制模式,进制符:" + Characters.Join("");
  257. }
  258. }