UnicodeFormater.cs 10 KB

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