NumberFormater.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Globalization;
  4. using System.Linq;
  5. using System.Numerics;
  6. using System.Text.RegularExpressions;
  7. namespace Masuit.Tools.Strings
  8. {
  9. /// <summary>
  10. /// 数制格式化器
  11. /// </summary>
  12. public class NumberFormater
  13. {
  14. /// <summary>
  15. /// 数制表示字符集
  16. /// </summary>
  17. private string Characters { get; set; }
  18. /// <summary>
  19. /// 进制长度
  20. /// </summary>
  21. public int Length => Characters.Length;
  22. /// <summary>
  23. /// 起始值偏移
  24. /// </summary>
  25. private readonly byte _offset;
  26. /// <summary>
  27. /// 数制格式化器
  28. /// </summary>
  29. public NumberFormater()
  30. {
  31. Characters = "0123456789";
  32. }
  33. /// <summary>
  34. /// 数制格式化器
  35. /// </summary>
  36. /// <param name="characters">符号集</param>
  37. /// <param name="offset">起始值偏移</param>
  38. public NumberFormater(string characters, byte offset = 0)
  39. {
  40. if (string.IsNullOrEmpty(characters))
  41. {
  42. throw new ArgumentException("符号集不能为空");
  43. }
  44. Characters = characters;
  45. _offset = offset;
  46. }
  47. /// <summary>
  48. /// 数制格式化器
  49. /// </summary>
  50. /// <param name="base">进制</param>
  51. /// <param name="offset">起始值偏移</param>
  52. public NumberFormater(byte @base, byte offset = 0)
  53. {
  54. if (@base < 2)
  55. {
  56. @base = 2;
  57. }
  58. if (@base > 64)
  59. {
  60. throw new ArgumentException("默认进制最大支持64进制");
  61. }
  62. Characters = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/".Substring(0, @base);
  63. if (offset >= @base)
  64. {
  65. throw new ArgumentException("偏移量不能超过进制基数" + @base);
  66. }
  67. _offset = offset;
  68. }
  69. /// <summary>
  70. /// 数字转换为指定的进制形式字符串
  71. /// </summary>
  72. /// <param name="number"></param>
  73. /// <returns></returns>
  74. public string ToString(long number)
  75. {
  76. int start = 0;
  77. int resultOffset = 0;
  78. if (_offset > 0)
  79. {
  80. start = 1;
  81. resultOffset = _offset - 1;
  82. }
  83. number = number - resultOffset;
  84. List<string> result = new List<string>();
  85. long t = Math.Abs(number);
  86. while (t != 0)
  87. {
  88. var mod = t % Length;
  89. t = Math.Abs(t / Length);
  90. var character = Characters[Convert.ToInt32(mod) - start].ToString();
  91. result.Insert(0, character);
  92. }
  93. if (number < 0)
  94. {
  95. result.Insert(0, "-");
  96. }
  97. return string.Join("", result);
  98. }
  99. /// <summary>
  100. /// 数字转换为指定的进制形式字符串
  101. /// </summary>
  102. /// <param name="number"></param>
  103. /// <returns></returns>
  104. public string ToString(BigInteger number)
  105. {
  106. int start = 0;
  107. int resultOffset = 0;
  108. if (_offset > 0)
  109. {
  110. start = 1;
  111. resultOffset = _offset - 1;
  112. }
  113. number = number - resultOffset;
  114. List<string> result = new List<string>();
  115. if (number < 0)
  116. {
  117. number = -number;
  118. result.Add("0");
  119. }
  120. BigInteger t = number;
  121. while (t != 0)
  122. {
  123. var mod = t % Length;
  124. t = BigInteger.Abs(BigInteger.Divide(t, Length));
  125. var character = Characters[(int)mod - start].ToString();
  126. result.Insert(0, character);
  127. }
  128. return string.Join("", result);
  129. }
  130. /// <summary>
  131. /// 指定字符串转换为指定进制的数字形式
  132. /// </summary>
  133. /// <param name="str"></param>
  134. /// <returns></returns>
  135. public long FromString(string str)
  136. {
  137. byte start = 0;
  138. int resultOffset = 0;
  139. if (_offset > 0)
  140. {
  141. start = 1;
  142. resultOffset = _offset - 1;
  143. }
  144. int j = 0;
  145. return new string(str.ToCharArray().Reverse().ToArray()).Where(ch => Characters.Contains(ch)).Sum(ch => (Characters.IndexOf(ch) + start) * (long)Math.Pow(Length, j++)) + resultOffset;
  146. }
  147. /// <summary>
  148. /// 指定字符串转换为指定进制的大数形式
  149. /// </summary>
  150. /// <param name="str"></param>
  151. /// <returns></returns>
  152. public BigInteger FromStringBig(string str)
  153. {
  154. byte start = 0;
  155. int resultOffset = 0;
  156. if (_offset > 0)
  157. {
  158. start = 1;
  159. resultOffset = _offset - 1;
  160. }
  161. int j = 0;
  162. var chars = new string(str.ToCharArray().Reverse().ToArray()).Where(ch => Characters.Contains(ch));
  163. return chars.Aggregate(BigInteger.Zero, (current, c) => current + (Characters.IndexOf(c) + start) * BigInteger.Pow(Length, j++)) + resultOffset;
  164. }
  165. /// <summary>Returns a string that represents the current object.</summary>
  166. /// <returns>A string that represents the current object.</returns>
  167. public override string ToString()
  168. {
  169. return Length + "进制模式,进制符:" + Characters;
  170. }
  171. // 转换数字
  172. private static char ToNum(char x)
  173. {
  174. string strChnNames = "零一二三四五六七八九";
  175. string strNumNames = "0123456789";
  176. return strChnNames[strNumNames.IndexOf(x)];
  177. }
  178. // 转换万以下整数
  179. private static string ChangeInt(string x)
  180. {
  181. string[] strArrayLevelNames = { "", "十", "百", "千" };
  182. string ret = "";
  183. int i;
  184. for (i = x.Length - 1; i >= 0; i--)
  185. {
  186. if (x[i] == '0')
  187. {
  188. ret = ToNum(x[i]) + ret;
  189. }
  190. else
  191. {
  192. ret = ToNum(x[i]) + strArrayLevelNames[x.Length - 1 - i] + ret;
  193. }
  194. }
  195. while ((i = ret.IndexOf("零零", StringComparison.Ordinal)) != -1)
  196. {
  197. ret = ret.Remove(i, 1);
  198. }
  199. if (ret[ret.Length - 1] == '零' && ret.Length > 1)
  200. {
  201. ret = ret.Remove(ret.Length - 1, 1);
  202. }
  203. if (ret.Length >= 2 && ret.Substring(0, 2) == "一十")
  204. {
  205. ret = ret.Remove(0, 1);
  206. }
  207. return ret;
  208. }
  209. // 转换整数
  210. private static string ToInt(string x)
  211. {
  212. int len = x.Length;
  213. string result;
  214. string temp;
  215. if (len <= 4)
  216. {
  217. result = ChangeInt(x);
  218. }
  219. else if (len <= 8)
  220. {
  221. result = ChangeInt(x.Substring(0, len - 4)) + "万";
  222. temp = ChangeInt(x.Substring(len - 4, 4));
  223. if (temp.IndexOf("千", StringComparison.Ordinal) == -1 && !string.IsNullOrEmpty(temp))
  224. {
  225. result += "零" + temp;
  226. }
  227. else
  228. {
  229. result += temp;
  230. }
  231. }
  232. else
  233. {
  234. result = ChangeInt(x.Substring(0, len - 8)) + "亿";
  235. temp = ChangeInt(x.Substring(len - 8, 4));
  236. if (temp.IndexOf("千", StringComparison.Ordinal) == -1 && !string.IsNullOrEmpty(temp))
  237. {
  238. result += "零" + temp;
  239. }
  240. else
  241. {
  242. result += temp;
  243. }
  244. result += "万";
  245. temp = ChangeInt(x.Substring(len - 4, 4));
  246. if (temp.IndexOf("千", StringComparison.Ordinal) == -1 && !string.IsNullOrEmpty(temp))
  247. {
  248. result += "零" + temp;
  249. }
  250. else
  251. {
  252. result += temp;
  253. }
  254. }
  255. int i;
  256. if ((i = result.IndexOf("零万", StringComparison.Ordinal)) != -1)
  257. {
  258. result = result.Remove(i + 1, 1);
  259. }
  260. while ((i = result.IndexOf("零零", StringComparison.Ordinal)) != -1)
  261. {
  262. result = result.Remove(i, 1);
  263. }
  264. if (result[result.Length - 1] == '零' && result.Length > 1)
  265. {
  266. result = result.Remove(result.Length - 1, 1);
  267. }
  268. return result;
  269. }
  270. /// <summary>
  271. /// 转换为中文数字格式
  272. /// </summary>
  273. /// <param name="num">123.45</param>
  274. /// <returns></returns>
  275. public static string ToChineseNumber(double num)
  276. {
  277. var x = num.ToString(CultureInfo.CurrentCulture);
  278. if (x.Length == 0)
  279. {
  280. return "";
  281. }
  282. string result = "";
  283. if (x[0] == '-')
  284. {
  285. result = "负";
  286. x = x.Remove(0, 1);
  287. }
  288. if (x[0].ToString() == ".")
  289. {
  290. x = "0" + x;
  291. }
  292. if (x[x.Length - 1].ToString() == ".")
  293. {
  294. x = x.Remove(x.Length - 1, 1);
  295. }
  296. if (x.IndexOf(".") > -1)
  297. {
  298. result += ToInt(x.Substring(0, x.IndexOf("."))) + "点" + x.Substring(x.IndexOf(".") + 1).Aggregate("", (current, t) => current + ToNum(t));
  299. }
  300. else
  301. {
  302. result += ToInt(x);
  303. }
  304. return result;
  305. }
  306. /// <summary>
  307. /// 数字转中文金额大写
  308. /// </summary>
  309. /// <param name="number">22.22</param>
  310. /// <returns></returns>
  311. public static string ToChineseMoney(double number)
  312. {
  313. string s = number.ToString("#L#E#D#C#K#E#D#C#J#E#D#C#I#E#D#C#H#E#D#C#G#E#D#C#F#E#D#C#.0B0A");
  314. string d = Regex.Replace(s, @"((?<=-|^)[^1-9]*)|((?'z'0)[0A-E]*((?=[1-9])|(?'-z'(?=[F-L\.]|$))))|((?'b'[F-L])(?'z'0)[0A-L]*((?=[1-9])|(?'-z'(?=[\  .]|$))))", "${b}${z}");
  315. return Regex.Replace(d, ".", m => "负元空零壹贰叁肆伍陆柒捌玖空空空空空空空分角拾佰仟萬億兆京垓秭穰"[m.Value[0] - '-'].ToString());
  316. }
  317. }
  318. }