【C#】【Demo】生成编号算法
using PetsMall.Common; using PetsMall.Model.Entites; using System; using System.Collections.Generic; using System.Linq; namespace CommonUtil { /// <summary> /// 生成编号 /// 编号模拟数字进制规则,可以用一个数字序号表示,字符在字符数组中下标表示数值,如编号“0”等于序号0,如字符集Sort中编号“A”等于序号9。 /// 编号转为常见进制的序号,表示的数值可能非常大,无法计算。固用int数组内每个数值表示每个字符在字符数组下标,来转换数字和字符。 /// 可用构造参数设置初始编号,序号将从初始编号开始,即初始编号等于序号0; /// /// 例如ReportNumberSort为自增 /// testItem.ReportNumber = ""; /// db.Set<Order_TestItem>().Add(testItem); /// db.SaveChanges(); /// testItem.ReportNumber = NumberCreateHelper.NotSort.No_SortToNumberString(testItem.ReportNumberSort); /// db.SaveChanges(); /// </summary> public class NumberCreateHelper { /// <summary> /// 生成编号显示字符,字符顺序 /// </summary> public static readonly NumberCreateHelper Sort = new NumberCreateHelper(new char[] { '0', '1', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'K', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'X', 'Y', 'Z' } , ConfigurationHelper.AppSetting("NumberCreateHelper_InitNumber_Sort")); /// <summary> /// 生成编号显示字符,乱序 /// </summary> public static readonly NumberCreateHelper NotSort = new NumberCreateHelper(new char[] { 'D', 'E', '0', '1', 'Q', 'C', 'F', 'G', '5', 'N', 'P', 'M', '6', 'R', 'X', '7', 'K', '8', 'S', 'T', '9', 'A', '3', '4', 'B', 'H', 'Y', 'Z' } , ConfigurationHelper.AppSetting("NumberCreateHelper_InitNumber_NotSort")); readonly char[] NO_pattern; readonly List<char> NO_patternList; readonly string initNumber; readonly int[] initInts; private NumberCreateHelper() { } /// <summary> /// /// </summary> /// <param name="_NO_pattern">使用字符集,字符集下标对应int数组的数值,与int数组转换</param> /// <param name="_initNumber">初始编号,使用序号取编号,将从初始编号开始,初始编号等于序号0</param> private NumberCreateHelper(char[] _NO_pattern, string _initNumber = "") { if (_NO_pattern != null) { NO_pattern = _NO_pattern; } NO_patternList = NO_pattern.ToList(); if (string.IsNullOrWhiteSpace(_initNumber)) { _initNumber = NO_pattern[0].ToString(); } initNumber = _initNumber; initInts = NO_NumberStringToInts(initNumber); } #region 生成编号 /// <summary> /// 生成编号 /// </summary> /// <param name="len">编号位数</param> /// <param name="v">编号数值</param> /// <returns></returns> public string NO_CreateNumberString(int len, out int[] v) { //生成len个小于_pattern.Length的整数 Random random = new Random(~unchecked((int)DateTime.Now.Ticks)); v = new int[len]; string nu = ""; for (int i = 0; i < len; i++) { v[i] = random.Next(0, NO_pattern.Length); nu += NO_pattern[v[i]]; } return nu; } /// <summary> /// 下一个编号 /// </summary> /// <returns></returns> public string NO_NumberStringNext(string nu) { var v = NO_NumberStringToInts(nu); v = NO_IntsIncreaseOne(v); return NO_IntsToNumberString(v); } /// <summary> /// int数组转编号字符 /// </summary> /// <param name="nu"></param> /// <returns></returns> public string NO_IntsToNumberString(int[] v) { string nu = ""; for (int i = 0; i < v.Length; i++) { nu += NO_pattern[v[i]]; } return nu; } /// <summary> /// 编号字符转int数组 /// </summary> /// <param name="nu"></param> /// <returns></returns> public int[] NO_NumberStringToInts(string nu) { int[] v = new int[nu.Length]; for (int i = 0; i < nu.Length; i++) { v[i] = NO_patternList.IndexOf(nu[i]); } return v; } /// <summary> /// int数组增加1 /// </summary> /// <param name="v"></param> /// <param name="index">当前执行下标,初始请默认为null</param> /// <returns></returns> private int[] NO_IntsIncreaseOne(int[] v, int? index = null) { int i = index ?? v.Length - 1; if (i < 0) { //无法增加 throw new Exception("CreateReportNumberLast 无法增加,超出模块支持数字界限"); return null; } if (v[i] < NO_pattern.Length - 1) { v[i]++; return v; } else { v[i] = 0; return NO_IntsIncreaseOne(v, i - 1); } } /// <summary> /// int数组减少1 /// </summary> /// <param name="v"></param> /// <param name="index">当前执行下标,初始请默认为null</param> /// <returns></returns> private int[] NO_IntsReduceOne(int[] v, int? index = null) { int i = index ?? v.Length - 1; if (i < 0) { //无法减少 throw new Exception("CreateReportNumberLast 无法减少,模块不支持负数"); return null; } if (v[i] > 0) { v[i]--; return v; } else { v[i] = 0; return NO_IntsReduceOne(v, i - 1); } } /// <summary> /// 数组相减得到序号 /// </summary> /// <param name="left">数组减法左边</param> /// <param name="right">数组减法右边,被减去</param> /// <param name="index">当前执行以右侧开锁计算的下标,初始请默认为null</param> /// <param name="max">字符集长度表示数字数组长度,相当于进制上限</param> /// <returns></returns> private int No_IntsReduceInts(int[] left, int[] right, int? index = null, int max = 0) { //max类型进制位数,满max进1 if (max <= 0) { max = NO_pattern.Length; } //首次计算,将数组位数对齐 if (index == null) { var lList = left.ToList(); int lIndex = lList.FindIndex(x => x > 0); if (lIndex > 0) { //移除减数左边的0 lList.RemoveRange(0, lIndex); left = lList.ToArray(); } var rList = right.ToList(); int rIndex = rList.FindIndex(x => x > 0); if (rIndex < 0) { throw new Exception("CreateReportNumberLast 无法计算序号,被减编号数组为负"); ////减负数和0都不变 //return NO_IntsToInt(left); } else if (rIndex > 0) { //移除被减数左边的0 rList.RemoveRange(0, rIndex); right = rList.ToArray(); } if (right.Length > left.Length) { throw new Exception("CreateReportNumberLast 无法计算序号,被减编号数组长度大于原编号数组"); ////被减位数大于减数位数,不变 //return NO_IntsToInt(left); } index = right.Length - 1; } int i = index.Value; //计算数组相减 if (left[right.Length - left.Length + i] >= right[i]) { left[right.Length - left.Length + i] -= right[i]; i--; if (i < 0) { return NO_IntsToInt(left); } else { return No_IntsReduceInts(left, right, i); } } else { //无高位可取 if (right.Length - left.Length + i - 1 < 0) { throw new Exception("CreateReportNumberLast 无法计算序号,被减编号数组数值大于原编号数组"); } //取高位减,被取高位为0,则会为负1,下一次递归还会到这里继续取高位 left[right.Length - left.Length + i - 1]--; //如果当前位的left被上一次取高位到负1,则会到这里变为max-1。 left[right.Length - left.Length + i] += max; return No_IntsReduceInts(left, right, i); } } /// <summary> /// 顺序序号转数组 /// 编号表示数字很大,int类型不够作为参数用此方法转换,需配合初始编号使用 /// </summary> /// <param name="sort"></param> /// <returns></returns> public int[] NO_SortNoToInts(int sort, int minLen = 0, int max = 0) { //max类型进制位数,满max进1 if (max <= 0) { max = NO_pattern.Length; } List<int> res = new List<int>(); int now = sort; while (now > 0) { res.Add(now % max);//取余 now = now / max;//偏移 } //补充0, if (minLen > 0 && res.Count() < minLen) { int count = res.Count(); for (int i = 0; i < minLen - count; i++) { res.Add(0); } } res.Reverse(); return res.ToArray(); } /// <summary> /// 数组转顺序序号 /// 编号表示数字很大,容易数字溢出,需配合初始编号使用 /// </summary> /// <param name="ints"></param> /// <param name="max"></param> /// <returns></returns> public int NO_IntsToInt(int[] ints, int max = 0) { if (max <= 0) { max = NO_pattern.Length; } int res = 0;//ints[ints.Length-1] for (int i = ints.Length - 1; i > 0; i--) { res += (ints[i] * (int)Math.Pow(max, (ints.Length - 1) - i)); } if (res < 0) { throw new Exception("CreateReportNumberLast 无法转为序号,数组表示数值溢出"); } return res; } /// <summary> /// 序号转编号 /// </summary> /// <param name="sort"></param> /// <returns></returns> public string No_SortToNumberString(int sort) { int[] ints = new int[initInts.Length]; initInts.CopyTo(ints, 0); if (sort > 0) { for (int i = 0; i < sort; i++) { ints = NO_IntsIncreaseOne(ints); } } return NO_IntsToNumberString(ints); } /// <summary> /// 编号转序号 /// </summary> /// <param name="sort"></param> /// <returns></returns> public int No_NumberStringToSort(string nu) { int[] ints = new int[initInts.Length]; initInts.CopyTo(ints, 0); return No_IntsReduceInts(NO_NumberStringToInts(nu), ints); } #endregion } }