using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Reflection; using System.Linq.Expressions; using System.Collections; namespace MRMS.Utility { public static class OperateSerialNo { public static System.Text.RegularExpressions.Regex regex = new System.Text.RegularExpressions.Regex("[^0-9]"); /// /// 卡序列号加减运算(减操作时,参数addNum为负数) /// /// /// /// 返回值是否需要原来的运算值的位长对齐(主要用于减的情况和包装连操作) /// /// public static string CardSerialNoAddNum(string cardSerialNo, int addNum, bool needAlign=true) { if ((string.IsNullOrWhiteSpace(cardSerialNo))) { cardSerialNo = "0"; } cardSerialNo = cardSerialNo.Trim(); string getCardSerialNo = cardSerialNo; if (addNum == 0) { return getCardSerialNo; } if (IsNumber(cardSerialNo)) { getCardSerialNo = IsNumberStrValueAddNum(cardSerialNo, addNum, needAlign); } else { //包含有非数字字符,出现频率较小,对此要分开处理。 //记录 cardSerialNo 中的各个非数字字母和位置。 notNumLetterAndPlace[] supplyInfor = getstrValueNotNumPart(cardSerialNo); cardSerialNo = regex.Replace(cardSerialNo, ""); getCardSerialNo = IsNumberStrValueAddNum(cardSerialNo, addNum, needAlign); //对getCardSerialNo补加cardSerialNo 中的各个非数字字母。 getCardSerialNo = supplyStrValueNotNumPar(getCardSerialNo, supplyInfor); } return getCardSerialNo; } /// /// 得到起止序列号之间的卡数量,包括起止序列号卡本身。 /// /// /// /// 没意义的或异常的数值运算将返回 -1 public static int CardSerialNoContainNum(string serialNoBegin, string serialNoEnd) { int containNum = 1; if (string.IsNullOrWhiteSpace(serialNoBegin)) { serialNoBegin = "0"; } if (string.IsNullOrWhiteSpace(serialNoEnd)) { serialNoEnd = "0"; } serialNoBegin = serialNoBegin.Trim().ToLower(); serialNoEnd = serialNoEnd.Trim().ToLower(); //added by belyn 当票据的可用起止序列号都为0代表用完了 if (serialNoBegin == "0" && serialNoEnd == "0") { return 0; } if (serialNoBegin == serialNoEnd) { containNum = 1; return containNum; } if (IsNumber(serialNoBegin) && IsNumber(serialNoEnd)) { containNum = IsNumberStrValueCardSerialNoContainNum(serialNoBegin, serialNoEnd); } else { //包含有非数字字符,出现频率较小,对此要分开处理。 serialNoBegin = regex.Replace(serialNoBegin, ""); serialNoEnd = regex.Replace(serialNoEnd, ""); containNum = IsNumberStrValueCardSerialNoContainNum(serialNoBegin, serialNoEnd); } return containNum; } /// /// 将两个序列号拆分成序列号数组 /// /// /// /// public static IList SplitSerialNo(string serialNoBegin, string serialNoEnd) { int i; int count = CardSerialNoContainNum(serialNoBegin, serialNoEnd); IList result = new List(); if (count == -1) { throw(new OperateSerialNoException("序列号起止并非合法的序列号对,无法计算起止序列号之间的数量。")); } for (i = 0; i < count; i++) { result.Add(CardSerialNoAddNum(serialNoBegin, i)); } return result; } /// /// 得到起止序列号之间的卡数量,包括起止序列号卡本身。 /// /// 字符串中都是数字 /// 字符串中都是数字 /// 没意义的或异常的将抛出异常 private static int IsNumberStrValueCardSerialNoContainNum(string serialNoBegin, string serialNoEnd) { //从左边开头比较抵消处理。 //先判断是否有非数值字母,有的话要转变处理。 if (string.IsNullOrWhiteSpace(serialNoBegin)) { serialNoBegin = "0"; } if (string.IsNullOrWhiteSpace(serialNoEnd)) { serialNoEnd = "0"; } serialNoBegin = serialNoBegin.Trim().ToLower(); serialNoEnd = serialNoEnd.Trim().ToLower(); int serialNoBeginLen = serialNoBegin.Length; int serialNoEndLen = serialNoEnd.Length; Int64 containNum = 1; if (serialNoBegin.CompareTo(serialNoEnd) == 0) { //相同。 containNum = 1; } else { int leftPartSamLen; //左边边相同部分的长度;防止长字符,可以消减。 //相互比对左边补0;以使两个操作项位数相同。 if (serialNoBeginLen != serialNoEndLen) { if (serialNoBeginLen < serialNoEndLen) { serialNoBegin = serialNoBegin.PadLeft(serialNoEndLen, '0'); } else { serialNoEnd = serialNoEnd.PadLeft(serialNoBeginLen, '0'); } } if (serialNoBegin.CompareTo(serialNoEnd) == 0) { //相同。 containNum = 1; } else { string inBeginSingleStr; string inEndSingleStr; leftPartSamLen = 0; while ((leftPartSamLen + 1) <= serialNoBegin.Length) { inBeginSingleStr = serialNoBegin.Substring(leftPartSamLen, 1); inEndSingleStr = serialNoEnd.Substring(leftPartSamLen, 1); if (inBeginSingleStr == inEndSingleStr) { leftPartSamLen++; } else { break; } } string joinOperateSerialNoBegin; //参与运算的起序列号部分。 string joinOperateSerialNoEnd; //参与运算的止序列号部分。 joinOperateSerialNoBegin = serialNoBegin.Substring(leftPartSamLen); joinOperateSerialNoEnd = serialNoEnd.Substring(leftPartSamLen); try { containNum = System.Convert.ToInt64(joinOperateSerialNoEnd) - System.Convert.ToInt64(joinOperateSerialNoBegin) + 1; } catch (System.Exception err) { string errStr = err.Message; throw new OperateSerialNoException("操作数运算溢出异常!"); } } } return System.Convert.ToInt32(containNum); } /// /// 比较两个字符串的大小;后者不小于前者。 /// /// /// /// public static bool CompareNotLess(string lower, string upper) { bool checkResult = false; if ((string.IsNullOrWhiteSpace(lower))) { lower = "0"; } if ((string.IsNullOrWhiteSpace(upper))) { upper = "0"; } if (lower.Trim().ToLower() == upper.Trim().ToLower()) { checkResult = true; } else { if (CardSerialNoContainNum(lower, upper) >= 1) { checkResult = true; } } return checkResult; } /// /// 比较两个字符串的大小;后者大于前者。 /// /// /// /// public static bool CompareGreater(string lower, string upper) { bool checkResult = false; if ((string.IsNullOrWhiteSpace(lower))) { lower = "0"; } if ((string.IsNullOrWhiteSpace(upper))) { upper = "0"; } if (lower.Trim().ToLower() == upper.Trim().ToLower()) { checkResult = false; } else { if (CardSerialNoContainNum(lower, upper) > 1) { checkResult = true; } } return checkResult; } /// /// 判断字符串是否在下限、上限内。 /// /// /// /// /// public static bool CheckRangeContentedValue(string lower, string upper, string checkValue) { bool checkResult = false; if ((string.IsNullOrWhiteSpace(lower))) { lower = "0"; } if ((string.IsNullOrWhiteSpace(upper))) { upper = "0"; } if ((string.IsNullOrWhiteSpace(checkValue))) { checkValue = "0"; } if (lower.Trim() == "0" && upper.Trim() == "0" && checkValue.Trim() != "0") return false; if (lower.Trim() == "0" && upper.Trim() == "0" && checkValue.Trim() == "0") return true; if (CardSerialNoContainNum(lower, checkValue) >= 1 && CardSerialNoContainNum(checkValue, upper) >= 1 ) { checkResult = true; } return checkResult; } /// /// 记录非数字的字母和字母位置 /// public struct notNumLetterAndPlace { public string notNumLetter; //非数字字母 public int LetterPlace; //该字母在字符串中的位置,和string定义的位置一致,0开始从左到右。 } /// /// 根据字母和位置信息给字符串补充字母。-1标记不补充,补充操作从左到右不可反向。(要考虑位不足) /// /// private static string supplyStrValueNotNumPar(string strValue, notNumLetterAndPlace[] supplyInfor) { string getStrValue = strValue; int supplyInforLen = supplyInfor.Length; //获取最大位置的非字母的位置,如果需要插入的原始值位数小于该值,则需要前边不0。 int needMinShort = 0; for (int leftFirtCharPlace = 0; leftFirtCharPlace < supplyInforLen; leftFirtCharPlace++) { if (supplyInfor[leftFirtCharPlace].LetterPlace != -1) { needMinShort = supplyInforLen-leftFirtCharPlace+1; } } if (strValue.Length < needMinShort) { strValue = strValue.PadLeft(needMinShort, '0'); } for (int letterPlaceIndex = 0; letterPlaceIndex < supplyInforLen; letterPlaceIndex++) { if (supplyInfor[letterPlaceIndex].LetterPlace != -1) { //补充操作 getStrValue = getStrValue.Insert(supplyInfor[letterPlaceIndex].LetterPlace, supplyInfor[letterPlaceIndex].notNumLetter); } } return getStrValue; } /// /// 长数字字符的加运算(包括减运算) /// /// 字符串中都是数字 /// /// 是否需要位长对齐(主要用于减的情况) /// private static string IsNumberStrValueAddNum(string strValue, int addNum, bool needAlign = true) { strValue = strValue.Trim(); if (strValue == "" || strValue == null || string.Equals(strValue, System.String.Empty)) { strValue = "0"; } string resultStrValue; int strValueLen; //字符串长度,即 strValue 的长度。 strValueLen = strValue.Length; //int nowDoDegreeHigh; //当前处理的高位位置(从右到左,和整数位数定义一致)。 //int nowDoNumLen; //当次运算涉及到的位数。 //int nowDoDegreeLow; //当前处理的底位位置(从右到左,和整数位数定义一致)。 //Int64 joinNumInStrValue; //要参与当次运算的字符串部分数值。 //Int64 joinNumInRemnant; //剩余要加的数量,开始时是 要加数量。 //nowDoNumLen = addNum.ToString().Length; //第一次运算涉及到的位数是传入的要加数量的位数。 //nowDoDegreeHigh = addNum.ToString().Length; //nowDoDegreeLow = 1; int canDoIntMaxLen = 18; if (strValueLen <= canDoIntMaxLen) { //位整型最大值19位,可直接运算后返回。 resultStrValue = System.Convert.ToString(System.Convert.ToInt64(strValue) + addNum); } else { #region 不再使用递归处理,而是直接取后18位来处理;然后补加左边。 /* 不再使用递归处理,而是直接取后18位来处理;然后补加左边。 //加的超常位的,从右到左递推计算。 resultStrValue = ""; joinNumInRemnant = addNum; while (nowDoDegreeHigh < strValueLen) { nowDoNumLen = joinNumInRemnant.ToString().Length; joinNumInStrValue = System.Convert.ToInt64(strValue.Substring((strValueLen - nowDoDegreeHigh), nowDoNumLen)); joinNumInRemnant = joinNumInStrValue + joinNumInRemnant; //resultStrValue = System.Convert.ToString(joinNumInRemnant) + resultStrValue; //判断是否进位 if (joinNumInRemnant.ToString().Length <= nowDoNumLen) { //没进位,结束循环。 resultStrValue = System.Convert.ToString(joinNumInRemnant) + resultStrValue; break; } else { //进位 resultStrValue = (System.Convert.ToString(joinNumInRemnant)).Substring(1) + resultStrValue; joinNumInRemnant = 1; //只有1这个值。(System.Convert.ToString(joinNumInRemnant)).Substring(1) nowDoDegreeHigh = nowDoDegreeHigh + 1; nowDoDegreeLow = nowDoDegreeHigh; } } */ #endregion string canDoMaxRightPar = strValue.Substring((strValueLen - canDoIntMaxLen), canDoIntMaxLen); string strLowPlaceValue = System.Convert.ToString(System.Convert.ToInt64(canDoMaxRightPar) + addNum); resultStrValue = strValue.Substring(0, (strValue.Length - strLowPlaceValue.Length)) + strLowPlaceValue; } if (needAlign) { resultStrValue = supplyleftPart(resultStrValue, strValue, addNum); } return resultStrValue; } /// /// 根据参照字符串,补充左边缺的部分,如0开头的。 /// /// /// /// private static string supplyleftPart(string strValueNeedSupply, string strValueRefer, int addNum) { string resultStrValue; if (strValueNeedSupply.Length >= strValueRefer.Length) { //不需要补充 resultStrValue = strValueNeedSupply; } else { //不可简单的在左边补0; //resultStrValue = strValueRefer.Substring(0, (strValueRefer.Length - strValueNeedSupply.Length)) + strValueNeedSupply; //resultStrValue = strValueNeedSupply.PadLeft(strValueRefer.Length, '0'); if (addNum >= 0) { resultStrValue = strValueRefer.Substring(0, (strValueRefer.Length - strValueNeedSupply.Length)) + strValueNeedSupply; } else { resultStrValue = strValueNeedSupply.PadLeft(strValueRefer.Length, '0'); } } return resultStrValue; } public static notNumLetterAndPlace[] getstrValueNotNumPart(string strValue) { notNumLetterAndPlace[] getValue = new notNumLetterAndPlace[strValue.Length]; string Letter; for (int i = 0; i < strValue.Length; i++) { Letter = strValue.Substring(i, 1); if (regex.IsMatch(Letter)) { //是非数字字母 getValue[i].notNumLetter = Letter; getValue[i].LetterPlace = i; } else { getValue[i].LetterPlace = -1; //是数字字母,标位置为-1。 } } return getValue; } /// /// 判断该字符串是否全数字 /// 注意: "" 返回是false. /// /// /// public static bool IsNumber(string strNumber) { //bool b = System.Text.RegularExpressions.Regex.IsMatch(strNumber, @"^(-?\\d+)(\\.\\d+)?$"); return System.Text.RegularExpressions.Regex.IsMatch(strNumber, @"^(-?\d+$)"); } /// /// 判断字符串是否为正整数 /// /// 要判断的字符串对象 /// public static bool IsInt(string str) { return System.Text.RegularExpressions.Regex.IsMatch(str, @"^(0|([1-9]\d*))$"); } public static string[][] MergeSerialNo(string[] singleSerialNos) { int i; ArrayList result = new ArrayList(); string lastSerialNo = ""; string serialNoFirst = ""; for (i = 0; i < singleSerialNos.Length; i++) { if (lastSerialNo == "") { lastSerialNo = singleSerialNos[i]; serialNoFirst = lastSerialNo; continue; } if (singleSerialNos[i] != CardSerialNoAddNum(lastSerialNo, 1)) { result.Add(new string[] { serialNoFirst, lastSerialNo }); serialNoFirst = singleSerialNos[i]; } lastSerialNo = singleSerialNos[i]; } if (serialNoFirst != "" && lastSerialNo != "") { result.Add(new string[] { serialNoFirst, lastSerialNo }); } return (string[][])result.ToArray(typeof(string[])); } /// /// 将分段的序列号合成整体 /// /// 输入的数据源 /// 序列号起字段 /// 序列号止字段 /// 用于存放合并后区间序列号数量的字段 /// 需要合并的数据的筛选条件,不符合该条件的数据原封不动返回 /// 合并时的分组条件字段 /// public static IList MergeSerialNo(IEnumerable source, Expression> serialNoStart, Expression> serialNoEnd, Expression> qty, Expression> mergeCondition) where T : class { return MergeSerialNo(source, serialNoStart, serialNoEnd, qty, mergeCondition, (x => x)); } public static IList MergeSerialNo(IEnumerable source, Expression> serialNoStart, Expression> serialNoEnd, Expression> qty, Expression> mergeCondition, Expression> groupBy) { IList result = new List(); IList needMergeRowsList = new List(); PropertyInfo[] allProperties = typeof(T).GetProperties(); PropertyInfo[] groupProperties = typeof(GroupByCondition).GetProperties(); if (serialNoStart.Body.NodeType != ExpressionType.MemberAccess) { throw new OperateSerialNoException("serialNoStart必须为属性选择的Expression。"); } if (serialNoEnd.Body.NodeType != ExpressionType.MemberAccess) { throw new OperateSerialNoException("serialNoEnd必须为属性选择的Expression。"); } var qtyNodeType = qty.Body.NodeType; if (qtyNodeType == ExpressionType.Convert) { qtyNodeType = (qty.Body as UnaryExpression).Operand.NodeType; } if (qtyNodeType != ExpressionType.MemberAccess && qty.Body.ToString() != "null") { throw new OperateSerialNoException("qty必须为属性选择的Expression,如传入的对象没有任何表示数量的列,则直接输入如:x => null。"); } string serialNoStartColumnName = (serialNoStart.Body as MemberExpression).Member.Name; string serialNoEndColumnName = (serialNoEnd.Body as MemberExpression).Member.Name; string qtyColumnName; if (qty.Body.ToString() != "null") { if (qty.Body.NodeType == ExpressionType.Convert) { qtyColumnName = ((qty.Body as UnaryExpression).Operand as MemberExpression).Member.Name; } else { qtyColumnName = (qty.Body as MemberExpression).Member.Name; } } else { qtyColumnName = ""; } var serialNoStartFunc = serialNoStart.Compile(); var serialNoEndFunc = serialNoEnd.Compile(); var qtyFunc = qty.Compile(); var mergeConditionFunc = mergeCondition.Compile(); var groupByFunc = groupBy.Compile(); needMergeRowsList = source.Where(mergeCondition.Compile()).ToList(); result = ( from s in source join nmr in needMergeRowsList on new { Group = groupByFunc.Invoke(s), SerialNoStart = serialNoStartFunc.Invoke(s), SerialNoEnd = serialNoEndFunc.Invoke(s) } equals new { Group = groupByFunc.Invoke(nmr), SerialNoStart = serialNoStartFunc.Invoke(nmr), SerialNoEnd = serialNoEndFunc.Invoke(nmr) } into dnmr from enmr in dnmr.DefaultIfEmpty() where enmr == null select s ).ToList(); var startSerialNoList = ( from nmr in needMergeRowsList join nmr1 in needMergeRowsList on new { Group = groupByFunc.Invoke(nmr), SerialNo = CardSerialNoAddNum(serialNoStartFunc.Invoke(nmr), -1) } equals new { Group = groupByFunc.Invoke(nmr1), SerialNo = serialNoEndFunc.Invoke(nmr1) } into dnmr from enmr in dnmr.DefaultIfEmpty() where enmr == null select new { Group = groupByFunc.Invoke(nmr), SerialNo = serialNoStartFunc.Invoke(nmr), IsEnd = false } ); var endSerialNoList = ( from nmr in needMergeRowsList join nmr1 in needMergeRowsList on new { Group = groupByFunc.Invoke(nmr), SerialNo = CardSerialNoAddNum(serialNoEndFunc.Invoke(nmr), 1) } equals new { Group = groupByFunc.Invoke(nmr1), SerialNo = serialNoStartFunc.Invoke(nmr1) } into dnmr from enmr in dnmr.DefaultIfEmpty() where enmr == null select new { Group = groupByFunc.Invoke(nmr), SerialNo = serialNoEndFunc.Invoke(nmr), IsEnd = true } ); var serialNoList = startSerialNoList.Union(endSerialNoList).ToList(); if (groupProperties.Length > 0) { var orderingSerialNoList = serialNoList.OrderBy(x => groupProperties[0].GetValue(x.Group, null)); for (int i = 1; i < groupProperties.Length; i++) { orderingSerialNoList.ThenBy(x => groupProperties[i].GetValue(x.Group, null)); } orderingSerialNoList = orderingSerialNoList.ThenBy(x => x.SerialNo); serialNoList = orderingSerialNoList.ToList(); } string lastStartSerialNo = ""; foreach (var serialNo in serialNoList) { if (!serialNo.IsEnd) { lastStartSerialNo = serialNo.SerialNo; } else { T item = (T)typeof(T).Assembly.CreateInstance(typeof(T).FullName); //AutoMapper.Mapper.Map(item, serialNo.Group); foreach (var property in groupProperties) { allProperties.Where(x => x.Name == property.Name).First().SetValue(item, property.GetValue(serialNo.Group, null), null); } allProperties.Where(x => x.Name == serialNoStartColumnName).First().SetValue(item, lastStartSerialNo, null); allProperties.Where(x => x.Name == serialNoEndColumnName).First().SetValue(item, serialNo.SerialNo, null); if (qtyColumnName != "") { allProperties.Where(x => x.Name == qtyColumnName).First().SetValue(item, CardSerialNoContainNum(lastStartSerialNo, serialNo.SerialNo), null); } result.Add(item); } } return result; } public static string GetMaxSerialNo(string serialNo1, string serialNo2) { return CompareGreater(serialNo1, serialNo2) ? serialNo2 : serialNo1; } public static string GetMinSerialNo(string serialNo1, string serialNo2) { return CompareGreater(serialNo1, serialNo2) ? serialNo1 : serialNo2; } /// /// 获取两个字符串的相同开头 /// /// /// /// public static string GetSameStart(string string1, string string2) { int i; int minLength; int differentIndex = -1; char[] char1, char2; if (string1 == "" || string2 == "") { return ""; } if (string1.Length > string2.Length) { minLength = string2.Length; } else { minLength = string1.Length; } char1 = string1.ToCharArray(); char2 = string2.ToCharArray(); for (i = 0; i < minLength; i++) { if (char1[i] != char2[i]) { differentIndex = i; break; } } if (differentIndex != -1) { return string1.Substring(0, differentIndex); } else { return string1.Substring(0, minLength); } } public static string TrimStart(string source, string trimString) { int i; if (source == "" || trimString == "") { return ""; } if (trimString.Length > source.Length) { throw (new Exception("搜索的字符串长度超出源字符串范围。")); } if (!source.StartsWith(trimString)) { return source; } return source.Substring(trimString.Length, source.Length - trimString.Length); } public static IList SerialNoDecrease(this IList sourceList, IList decreasorList) { int i, j, k; IList resultList = null; foreach (var source in sourceList.OrderBy(x => x.SerialNoStart)) { string startSerialNo = source.SerialNoStart; string endSerialNo = source.SerialNoEnd; foreach (var decreasor in decreasorList.OrderBy(x => x.SerialNoStart)) { string decreaseStartSerialNo = decreasor.SerialNoStart; string decreaseEndSerialNo = decreasor.SerialNoEnd; try { if (decreaseStartSerialNo == "0" || decreaseEndSerialNo == "0") { continue; } if (startSerialNo.Length != decreaseStartSerialNo.Length) { continue; } string sameStart = GetSameStart(startSerialNo, decreaseStartSerialNo); string sameEnd = GetSameStart(endSerialNo, decreaseEndSerialNo); string sameAll = GetSameStart(sameStart, sameEnd); if (sameStart.Length == startSerialNo.Length && sameEnd.Length == endSerialNo.Length) { break; } if (!IsInt(TrimStart(startSerialNo, sameAll)) || !IsInt(TrimStart(decreaseStartSerialNo, sameAll)) || !IsInt(TrimStart(endSerialNo, sameAll)) || !IsInt(TrimStart(decreaseEndSerialNo, sameAll))) { continue; } int intStartSerialNo, intEndSerialNo, intDecreaseStartSerialNo, intDecreaseEndSerialNo; intStartSerialNo = Convert.ToInt32(TrimStart(startSerialNo, sameAll)); intEndSerialNo = Convert.ToInt32(TrimStart(endSerialNo, sameAll)); intDecreaseStartSerialNo = Convert.ToInt32(TrimStart(decreaseStartSerialNo, sameAll)); intDecreaseEndSerialNo = Convert.ToInt32(TrimStart(decreaseEndSerialNo, sameAll)); if (!(intStartSerialNo <= intDecreaseEndSerialNo && intEndSerialNo >= intDecreaseStartSerialNo)) { continue; } if (intStartSerialNo >= intDecreaseStartSerialNo && intEndSerialNo <= intDecreaseEndSerialNo) { break; } if (intStartSerialNo < intDecreaseStartSerialNo) { resultList.Add(new SerialNoSegment { SerialNoStart = startSerialNo, SerialNoEnd = CardSerialNoAddNum(decreaseStartSerialNo, -1) }); } if (intEndSerialNo > intDecreaseEndSerialNo) { startSerialNo = CardSerialNoAddNum(decreaseEndSerialNo, 1); resultList.Add(new SerialNoSegment { SerialNoStart = startSerialNo, SerialNoEnd = endSerialNo }); } else { startSerialNo = "0"; endSerialNo = "0"; } } catch (Exception ex) { throw (ex); } } } return resultList; } } public class SerialNoSegment { public string SerialNoStart { get; set; } public string SerialNoEnd { get; set; } } public class OperateSerialNoException : Exception { public OperateSerialNoException(string message) : base(message) { } public OperateSerialNoException(string message, Exception ex) : base(message, ex) { } } }