OperateSerialNo.cs 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Reflection;
  6. using System.Linq.Expressions;
  7. using System.Collections;
  8. namespace MRMS.Utility
  9. {
  10. public static class OperateSerialNo
  11. {
  12. public static System.Text.RegularExpressions.Regex regex = new System.Text.RegularExpressions.Regex("[^0-9]");
  13. /// <summary>
  14. /// 卡序列号加减运算(减操作时,参数addNum为负数)
  15. /// </summary>
  16. /// <param name="cardSerialNo"></param>
  17. /// <param name="AddNum"></param>
  18. /// <param name="needAlign">返回值是否需要原来的运算值的位长对齐(主要用于减的情况和包装连操作)</param>
  19. /// <returns></returns>
  20. ///
  21. public static string CardSerialNoAddNum(string cardSerialNo, int addNum, bool needAlign=true)
  22. {
  23. if ((string.IsNullOrWhiteSpace(cardSerialNo)))
  24. {
  25. cardSerialNo = "0";
  26. }
  27. cardSerialNo = cardSerialNo.Trim();
  28. string getCardSerialNo = cardSerialNo;
  29. if (addNum == 0)
  30. {
  31. return getCardSerialNo;
  32. }
  33. if (IsNumber(cardSerialNo))
  34. {
  35. getCardSerialNo = IsNumberStrValueAddNum(cardSerialNo, addNum, needAlign);
  36. }
  37. else
  38. { //包含有非数字字符,出现频率较小,对此要分开处理。
  39. //记录 cardSerialNo 中的各个非数字字母和位置。
  40. notNumLetterAndPlace[] supplyInfor = getstrValueNotNumPart(cardSerialNo);
  41. cardSerialNo = regex.Replace(cardSerialNo, "");
  42. getCardSerialNo = IsNumberStrValueAddNum(cardSerialNo, addNum, needAlign);
  43. //对getCardSerialNo补加cardSerialNo 中的各个非数字字母。
  44. getCardSerialNo = supplyStrValueNotNumPar(getCardSerialNo, supplyInfor);
  45. }
  46. return getCardSerialNo;
  47. }
  48. /// <summary>
  49. /// 得到起止序列号之间的卡数量,包括起止序列号卡本身。
  50. /// </summary>
  51. /// <param name="serialNoBegin"></param>
  52. /// <param name="serialNoEnd"></param>
  53. /// <returns>没意义的或异常的数值运算将返回 -1</returns>
  54. public static int CardSerialNoContainNum(string serialNoBegin, string serialNoEnd)
  55. {
  56. int containNum = 1;
  57. if (string.IsNullOrWhiteSpace(serialNoBegin))
  58. {
  59. serialNoBegin = "0";
  60. }
  61. if (string.IsNullOrWhiteSpace(serialNoEnd))
  62. {
  63. serialNoEnd = "0";
  64. }
  65. serialNoBegin = serialNoBegin.Trim().ToLower();
  66. serialNoEnd = serialNoEnd.Trim().ToLower();
  67. //added by belyn 当票据的可用起止序列号都为0代表用完了
  68. if (serialNoBegin == "0" && serialNoEnd == "0")
  69. {
  70. return 0;
  71. }
  72. if (serialNoBegin == serialNoEnd)
  73. {
  74. containNum = 1;
  75. return containNum;
  76. }
  77. if (IsNumber(serialNoBegin) && IsNumber(serialNoEnd))
  78. {
  79. containNum = IsNumberStrValueCardSerialNoContainNum(serialNoBegin, serialNoEnd);
  80. }
  81. else
  82. { //包含有非数字字符,出现频率较小,对此要分开处理。
  83. serialNoBegin = regex.Replace(serialNoBegin, "");
  84. serialNoEnd = regex.Replace(serialNoEnd, "");
  85. containNum = IsNumberStrValueCardSerialNoContainNum(serialNoBegin, serialNoEnd);
  86. }
  87. return containNum;
  88. }
  89. /// <summary>
  90. /// 将两个序列号拆分成序列号数组
  91. /// </summary>
  92. /// <param name="serialNoBegin"></param>
  93. /// <param name="serialNoEnd"></param>
  94. /// <returns></returns>
  95. public static IList<string> SplitSerialNo(string serialNoBegin, string serialNoEnd)
  96. {
  97. int i;
  98. int count = CardSerialNoContainNum(serialNoBegin, serialNoEnd);
  99. IList<string> result = new List<string>();
  100. if (count == -1)
  101. {
  102. throw(new OperateSerialNoException("序列号起止并非合法的序列号对,无法计算起止序列号之间的数量。"));
  103. }
  104. for (i = 0; i < count; i++)
  105. {
  106. result.Add(CardSerialNoAddNum(serialNoBegin, i));
  107. }
  108. return result;
  109. }
  110. /// <summary>
  111. /// 得到起止序列号之间的卡数量,包括起止序列号卡本身。
  112. /// </summary>
  113. /// <param name="serialNoBegin">字符串中都是数字</param>
  114. /// <param name="serialNoEnd">字符串中都是数字</param>
  115. /// <returns>没意义的或异常的将抛出异常</returns>
  116. private static int IsNumberStrValueCardSerialNoContainNum(string serialNoBegin, string serialNoEnd)
  117. { //从左边开头比较抵消处理。
  118. //先判断是否有非数值字母,有的话要转变处理。
  119. if (string.IsNullOrWhiteSpace(serialNoBegin))
  120. {
  121. serialNoBegin = "0";
  122. }
  123. if (string.IsNullOrWhiteSpace(serialNoEnd))
  124. {
  125. serialNoEnd = "0";
  126. }
  127. serialNoBegin = serialNoBegin.Trim().ToLower();
  128. serialNoEnd = serialNoEnd.Trim().ToLower();
  129. int serialNoBeginLen = serialNoBegin.Length;
  130. int serialNoEndLen = serialNoEnd.Length;
  131. Int64 containNum = 1;
  132. if (serialNoBegin.CompareTo(serialNoEnd) == 0)
  133. { //相同。
  134. containNum = 1;
  135. }
  136. else
  137. {
  138. int leftPartSamLen; //左边边相同部分的长度;防止长字符,可以消减。
  139. //相互比对左边补0;以使两个操作项位数相同。
  140. if (serialNoBeginLen != serialNoEndLen)
  141. {
  142. if (serialNoBeginLen < serialNoEndLen)
  143. {
  144. serialNoBegin = serialNoBegin.PadLeft(serialNoEndLen, '0');
  145. }
  146. else
  147. {
  148. serialNoEnd = serialNoEnd.PadLeft(serialNoBeginLen, '0');
  149. }
  150. }
  151. if (serialNoBegin.CompareTo(serialNoEnd) == 0)
  152. { //相同。
  153. containNum = 1;
  154. }
  155. else
  156. {
  157. string inBeginSingleStr;
  158. string inEndSingleStr;
  159. leftPartSamLen = 0;
  160. while ((leftPartSamLen + 1) <= serialNoBegin.Length)
  161. {
  162. inBeginSingleStr = serialNoBegin.Substring(leftPartSamLen, 1);
  163. inEndSingleStr = serialNoEnd.Substring(leftPartSamLen, 1);
  164. if (inBeginSingleStr == inEndSingleStr)
  165. {
  166. leftPartSamLen++;
  167. }
  168. else
  169. {
  170. break;
  171. }
  172. }
  173. string joinOperateSerialNoBegin; //参与运算的起序列号部分。
  174. string joinOperateSerialNoEnd; //参与运算的止序列号部分。
  175. joinOperateSerialNoBegin = serialNoBegin.Substring(leftPartSamLen);
  176. joinOperateSerialNoEnd = serialNoEnd.Substring(leftPartSamLen);
  177. try
  178. {
  179. containNum = System.Convert.ToInt64(joinOperateSerialNoEnd) - System.Convert.ToInt64(joinOperateSerialNoBegin) + 1;
  180. }
  181. catch (System.Exception err)
  182. {
  183. string errStr = err.Message;
  184. throw new OperateSerialNoException("操作数运算溢出异常!");
  185. }
  186. }
  187. }
  188. return System.Convert.ToInt32(containNum);
  189. }
  190. /// <summary>
  191. /// 比较两个字符串的大小;后者不小于前者。
  192. /// </summary>
  193. /// <param name="lower"></param>
  194. /// <param name="upper"></param>
  195. /// <returns></returns>
  196. public static bool CompareNotLess(string lower, string upper)
  197. {
  198. bool checkResult = false;
  199. if ((string.IsNullOrWhiteSpace(lower)))
  200. {
  201. lower = "0";
  202. }
  203. if ((string.IsNullOrWhiteSpace(upper)))
  204. {
  205. upper = "0";
  206. }
  207. if (lower.Trim().ToLower() == upper.Trim().ToLower())
  208. {
  209. checkResult = true;
  210. }
  211. else
  212. {
  213. if (CardSerialNoContainNum(lower, upper) >= 1)
  214. {
  215. checkResult = true;
  216. }
  217. }
  218. return checkResult;
  219. }
  220. /// <summary>
  221. /// 比较两个字符串的大小;后者大于前者。
  222. /// </summary>
  223. /// <param name="lower"></param>
  224. /// <param name="upper"></param>
  225. /// <returns></returns>
  226. public static bool CompareGreater(string lower, string upper)
  227. {
  228. bool checkResult = false;
  229. if ((string.IsNullOrWhiteSpace(lower)))
  230. {
  231. lower = "0";
  232. }
  233. if ((string.IsNullOrWhiteSpace(upper)))
  234. {
  235. upper = "0";
  236. }
  237. if (lower.Trim().ToLower() == upper.Trim().ToLower())
  238. {
  239. checkResult = false;
  240. }
  241. else
  242. {
  243. if (CardSerialNoContainNum(lower, upper) > 1)
  244. {
  245. checkResult = true;
  246. }
  247. }
  248. return checkResult;
  249. }
  250. /// <summary>
  251. /// 判断字符串是否在下限、上限内。
  252. /// </summary>
  253. /// <param name="lower"></param>
  254. /// <param name="upper"></param>
  255. /// <param name="checkValue"></param>
  256. /// <returns></returns>
  257. public static bool CheckRangeContentedValue(string lower, string upper, string checkValue)
  258. {
  259. bool checkResult = false;
  260. if ((string.IsNullOrWhiteSpace(lower)))
  261. {
  262. lower = "0";
  263. }
  264. if ((string.IsNullOrWhiteSpace(upper)))
  265. {
  266. upper = "0";
  267. }
  268. if ((string.IsNullOrWhiteSpace(checkValue)))
  269. {
  270. checkValue = "0";
  271. }
  272. if (lower.Trim() == "0" && upper.Trim() == "0" && checkValue.Trim() != "0") return false;
  273. if (lower.Trim() == "0" && upper.Trim() == "0" && checkValue.Trim() == "0") return true;
  274. if (CardSerialNoContainNum(lower, checkValue) >= 1
  275. && CardSerialNoContainNum(checkValue, upper) >= 1
  276. )
  277. {
  278. checkResult = true;
  279. }
  280. return checkResult;
  281. }
  282. /// <summary>
  283. /// 记录非数字的字母和字母位置
  284. /// </summary>
  285. public struct notNumLetterAndPlace
  286. {
  287. public string notNumLetter; //非数字字母
  288. public int LetterPlace; //该字母在字符串中的位置,和string定义的位置一致,0开始从左到右。
  289. }
  290. /// <summary>
  291. /// 根据字母和位置信息给字符串补充字母。-1标记不补充,补充操作从左到右不可反向。(要考虑位不足)
  292. /// </summary>
  293. /// <returns></returns>
  294. private static string supplyStrValueNotNumPar(string strValue, notNumLetterAndPlace[] supplyInfor)
  295. {
  296. string getStrValue = strValue;
  297. int supplyInforLen = supplyInfor.Length;
  298. //获取最大位置的非字母的位置,如果需要插入的原始值位数小于该值,则需要前边不0。
  299. int needMinShort = 0;
  300. for (int leftFirtCharPlace = 0; leftFirtCharPlace < supplyInforLen; leftFirtCharPlace++)
  301. {
  302. if (supplyInfor[leftFirtCharPlace].LetterPlace != -1)
  303. {
  304. needMinShort = supplyInforLen-leftFirtCharPlace+1;
  305. }
  306. }
  307. if (strValue.Length < needMinShort)
  308. {
  309. strValue = strValue.PadLeft(needMinShort, '0');
  310. }
  311. for (int letterPlaceIndex = 0; letterPlaceIndex < supplyInforLen; letterPlaceIndex++)
  312. {
  313. if (supplyInfor[letterPlaceIndex].LetterPlace != -1)
  314. { //补充操作
  315. getStrValue = getStrValue.Insert(supplyInfor[letterPlaceIndex].LetterPlace, supplyInfor[letterPlaceIndex].notNumLetter);
  316. }
  317. }
  318. return getStrValue;
  319. }
  320. /// <summary>
  321. /// 长数字字符的加运算(包括减运算)
  322. /// </summary>
  323. /// <param name="strValue">字符串中都是数字</param>
  324. /// <param name="addNum"></param>
  325. /// <param name="needAlign">是否需要位长对齐(主要用于减的情况)</param>
  326. /// <returns></returns>
  327. private static string IsNumberStrValueAddNum(string strValue, int addNum, bool needAlign = true)
  328. {
  329. strValue = strValue.Trim();
  330. if (strValue == "" || strValue == null || string.Equals(strValue, System.String.Empty))
  331. {
  332. strValue = "0";
  333. }
  334. string resultStrValue;
  335. int strValueLen; //字符串长度,即 strValue 的长度。
  336. strValueLen = strValue.Length;
  337. //int nowDoDegreeHigh; //当前处理的高位位置(从右到左,和整数位数定义一致)。
  338. //int nowDoNumLen; //当次运算涉及到的位数。
  339. //int nowDoDegreeLow; //当前处理的底位位置(从右到左,和整数位数定义一致)。
  340. //Int64 joinNumInStrValue; //要参与当次运算的字符串部分数值。
  341. //Int64 joinNumInRemnant; //剩余要加的数量,开始时是 要加数量。
  342. //nowDoNumLen = addNum.ToString().Length; //第一次运算涉及到的位数是传入的要加数量的位数。
  343. //nowDoDegreeHigh = addNum.ToString().Length;
  344. //nowDoDegreeLow = 1;
  345. int canDoIntMaxLen = 18;
  346. if (strValueLen <= canDoIntMaxLen)
  347. { //位整型最大值19位,可直接运算后返回。
  348. resultStrValue = System.Convert.ToString(System.Convert.ToInt64(strValue) + addNum);
  349. }
  350. else
  351. {
  352. #region 不再使用递归处理,而是直接取后18位来处理;然后补加左边。
  353. /* 不再使用递归处理,而是直接取后18位来处理;然后补加左边。
  354. //加的超常位的,从右到左递推计算。
  355. resultStrValue = "";
  356. joinNumInRemnant = addNum;
  357. while (nowDoDegreeHigh < strValueLen)
  358. {
  359. nowDoNumLen = joinNumInRemnant.ToString().Length;
  360. joinNumInStrValue = System.Convert.ToInt64(strValue.Substring((strValueLen - nowDoDegreeHigh), nowDoNumLen));
  361. joinNumInRemnant = joinNumInStrValue + joinNumInRemnant;
  362. //resultStrValue = System.Convert.ToString(joinNumInRemnant) + resultStrValue;
  363. //判断是否进位
  364. if (joinNumInRemnant.ToString().Length <= nowDoNumLen)
  365. { //没进位,结束循环。
  366. resultStrValue = System.Convert.ToString(joinNumInRemnant) + resultStrValue;
  367. break;
  368. }
  369. else
  370. { //进位
  371. resultStrValue = (System.Convert.ToString(joinNumInRemnant)).Substring(1) + resultStrValue;
  372. joinNumInRemnant = 1; //只有1这个值。(System.Convert.ToString(joinNumInRemnant)).Substring(1)
  373. nowDoDegreeHigh = nowDoDegreeHigh + 1;
  374. nowDoDegreeLow = nowDoDegreeHigh;
  375. }
  376. }
  377. */
  378. #endregion
  379. string canDoMaxRightPar = strValue.Substring((strValueLen - canDoIntMaxLen), canDoIntMaxLen);
  380. string strLowPlaceValue = System.Convert.ToString(System.Convert.ToInt64(canDoMaxRightPar) + addNum);
  381. resultStrValue = strValue.Substring(0, (strValue.Length - strLowPlaceValue.Length)) + strLowPlaceValue;
  382. }
  383. if (needAlign)
  384. {
  385. resultStrValue = supplyleftPart(resultStrValue, strValue, addNum);
  386. }
  387. return resultStrValue;
  388. }
  389. /// <summary>
  390. /// 根据参照字符串,补充左边缺的部分,如0开头的。
  391. /// </summary>
  392. /// <param name="strValue"></param>
  393. /// <param name="strValueRefer"></param>
  394. /// <returns></returns>
  395. private static string supplyleftPart(string strValueNeedSupply, string strValueRefer, int addNum)
  396. {
  397. string resultStrValue;
  398. if (strValueNeedSupply.Length >= strValueRefer.Length)
  399. { //不需要补充
  400. resultStrValue = strValueNeedSupply;
  401. }
  402. else
  403. {
  404. //不可简单的在左边补0;
  405. //resultStrValue = strValueRefer.Substring(0, (strValueRefer.Length - strValueNeedSupply.Length)) + strValueNeedSupply;
  406. //resultStrValue = strValueNeedSupply.PadLeft(strValueRefer.Length, '0');
  407. if (addNum >= 0)
  408. {
  409. resultStrValue = strValueRefer.Substring(0, (strValueRefer.Length - strValueNeedSupply.Length)) + strValueNeedSupply;
  410. }
  411. else
  412. {
  413. resultStrValue = strValueNeedSupply.PadLeft(strValueRefer.Length, '0');
  414. }
  415. }
  416. return resultStrValue;
  417. }
  418. public static notNumLetterAndPlace[] getstrValueNotNumPart(string strValue)
  419. {
  420. notNumLetterAndPlace[] getValue = new notNumLetterAndPlace[strValue.Length];
  421. string Letter;
  422. for (int i = 0; i < strValue.Length; i++)
  423. {
  424. Letter = strValue.Substring(i, 1);
  425. if (regex.IsMatch(Letter))
  426. { //是非数字字母
  427. getValue[i].notNumLetter = Letter;
  428. getValue[i].LetterPlace = i;
  429. }
  430. else
  431. {
  432. getValue[i].LetterPlace = -1; //是数字字母,标位置为-1。
  433. }
  434. }
  435. return getValue;
  436. }
  437. /// <summary>
  438. /// 判断该字符串是否全数字
  439. /// 注意: "" 返回是false.
  440. /// </summary>
  441. /// <param name="strNumber"></param>
  442. /// <returns></returns>
  443. public static bool IsNumber(string strNumber)
  444. {
  445. //bool b = System.Text.RegularExpressions.Regex.IsMatch(strNumber, @"^(-?\\d+)(\\.\\d+)?$");
  446. return System.Text.RegularExpressions.Regex.IsMatch(strNumber, @"^(-?\d+$)");
  447. }
  448. /// <summary>
  449. /// 判断字符串是否为正整数
  450. /// </summary>
  451. /// <param name="str">要判断的字符串对象</param>
  452. /// <returns></returns>
  453. public static bool IsInt(string str)
  454. {
  455. return System.Text.RegularExpressions.Regex.IsMatch(str, @"^(0|([1-9]\d*))$");
  456. }
  457. public static string[][] MergeSerialNo(string[] singleSerialNos)
  458. {
  459. int i;
  460. ArrayList result = new ArrayList();
  461. string lastSerialNo = "";
  462. string serialNoFirst = "";
  463. for (i = 0; i < singleSerialNos.Length; i++)
  464. {
  465. if (lastSerialNo == "")
  466. {
  467. lastSerialNo = singleSerialNos[i];
  468. serialNoFirst = lastSerialNo;
  469. continue;
  470. }
  471. if (singleSerialNos[i] != CardSerialNoAddNum(lastSerialNo, 1))
  472. {
  473. result.Add(new string[] { serialNoFirst, lastSerialNo });
  474. serialNoFirst = singleSerialNos[i];
  475. }
  476. lastSerialNo = singleSerialNos[i];
  477. }
  478. if (serialNoFirst != "" && lastSerialNo != "")
  479. { result.Add(new string[] { serialNoFirst, lastSerialNo }); }
  480. return (string[][])result.ToArray(typeof(string[]));
  481. }
  482. /// <summary>
  483. /// 将分段的序列号合成整体
  484. /// </summary>
  485. /// <param name="source">输入的数据源</param>
  486. /// <param name="serialNoStart">序列号起字段</param>
  487. /// <param name="serialNoEnd">序列号止字段</param>
  488. /// <param name="qty">用于存放合并后区间序列号数量的字段</param>
  489. /// <param name="mergeCondition">需要合并的数据的筛选条件,不符合该条件的数据原封不动返回</param>
  490. /// <param name="groupBy">合并时的分组条件字段</param>
  491. /// <returns></returns>
  492. public static IList<T> MergeSerialNo<T>(IEnumerable<T> source, Expression<Func<T, string>> serialNoStart, Expression<Func<T, string>> serialNoEnd,
  493. Expression<Func<T, int?>> qty, Expression<Func<T, bool>> mergeCondition) where T : class
  494. {
  495. return MergeSerialNo(source, serialNoStart, serialNoEnd, qty, mergeCondition, (x => x));
  496. }
  497. public static IList<T> MergeSerialNo<T, GroupByCondition>(IEnumerable<T> source, Expression<Func<T, string>> serialNoStart, Expression<Func<T, string>> serialNoEnd,
  498. Expression<Func<T, int?>> qty, Expression<Func<T, bool>> mergeCondition, Expression<Func<T, GroupByCondition>> groupBy)
  499. {
  500. IList<T> result = new List<T>();
  501. IList<T> needMergeRowsList = new List<T>();
  502. PropertyInfo[] allProperties = typeof(T).GetProperties();
  503. PropertyInfo[] groupProperties = typeof(GroupByCondition).GetProperties();
  504. if (serialNoStart.Body.NodeType != ExpressionType.MemberAccess)
  505. {
  506. throw new OperateSerialNoException("serialNoStart必须为属性选择的Expression。");
  507. }
  508. if (serialNoEnd.Body.NodeType != ExpressionType.MemberAccess)
  509. {
  510. throw new OperateSerialNoException("serialNoEnd必须为属性选择的Expression。");
  511. }
  512. var qtyNodeType = qty.Body.NodeType;
  513. if (qtyNodeType == ExpressionType.Convert)
  514. {
  515. qtyNodeType = (qty.Body as UnaryExpression).Operand.NodeType;
  516. }
  517. if (qtyNodeType != ExpressionType.MemberAccess && qty.Body.ToString() != "null")
  518. {
  519. throw new OperateSerialNoException("qty必须为属性选择的Expression,如传入的对象没有任何表示数量的列,则直接输入如:x => null。");
  520. }
  521. string serialNoStartColumnName = (serialNoStart.Body as MemberExpression).Member.Name;
  522. string serialNoEndColumnName = (serialNoEnd.Body as MemberExpression).Member.Name;
  523. string qtyColumnName;
  524. if (qty.Body.ToString() != "null")
  525. {
  526. if (qty.Body.NodeType == ExpressionType.Convert)
  527. {
  528. qtyColumnName = ((qty.Body as UnaryExpression).Operand as MemberExpression).Member.Name;
  529. }
  530. else
  531. {
  532. qtyColumnName = (qty.Body as MemberExpression).Member.Name;
  533. }
  534. }
  535. else
  536. {
  537. qtyColumnName = "";
  538. }
  539. var serialNoStartFunc = serialNoStart.Compile();
  540. var serialNoEndFunc = serialNoEnd.Compile();
  541. var qtyFunc = qty.Compile();
  542. var mergeConditionFunc = mergeCondition.Compile();
  543. var groupByFunc = groupBy.Compile();
  544. needMergeRowsList = source.Where(mergeCondition.Compile()).ToList();
  545. result = (
  546. from s in source
  547. join nmr in needMergeRowsList
  548. on new { Group = groupByFunc.Invoke(s), SerialNoStart = serialNoStartFunc.Invoke(s), SerialNoEnd = serialNoEndFunc.Invoke(s) }
  549. equals new { Group = groupByFunc.Invoke(nmr), SerialNoStart = serialNoStartFunc.Invoke(nmr), SerialNoEnd = serialNoEndFunc.Invoke(nmr) } into dnmr
  550. from enmr in dnmr.DefaultIfEmpty()
  551. where enmr == null
  552. select s
  553. ).ToList();
  554. var startSerialNoList = (
  555. from nmr in needMergeRowsList
  556. join nmr1 in needMergeRowsList
  557. on new { Group = groupByFunc.Invoke(nmr), SerialNo = CardSerialNoAddNum(serialNoStartFunc.Invoke(nmr), -1) }
  558. equals new { Group = groupByFunc.Invoke(nmr1), SerialNo = serialNoEndFunc.Invoke(nmr1) } into dnmr
  559. from enmr in dnmr.DefaultIfEmpty()
  560. where enmr == null
  561. select new
  562. {
  563. Group = groupByFunc.Invoke(nmr),
  564. SerialNo = serialNoStartFunc.Invoke(nmr),
  565. IsEnd = false
  566. }
  567. );
  568. var endSerialNoList = (
  569. from nmr in needMergeRowsList
  570. join nmr1 in needMergeRowsList
  571. on new { Group = groupByFunc.Invoke(nmr), SerialNo = CardSerialNoAddNum(serialNoEndFunc.Invoke(nmr), 1) }
  572. equals new { Group = groupByFunc.Invoke(nmr1), SerialNo = serialNoStartFunc.Invoke(nmr1) } into dnmr
  573. from enmr in dnmr.DefaultIfEmpty()
  574. where enmr == null
  575. select new
  576. {
  577. Group = groupByFunc.Invoke(nmr),
  578. SerialNo = serialNoEndFunc.Invoke(nmr),
  579. IsEnd = true
  580. }
  581. );
  582. var serialNoList = startSerialNoList.Union(endSerialNoList).ToList();
  583. if (groupProperties.Length > 0)
  584. {
  585. var orderingSerialNoList = serialNoList.OrderBy(x => groupProperties[0].GetValue(x.Group, null));
  586. for (int i = 1; i < groupProperties.Length; i++)
  587. {
  588. orderingSerialNoList.ThenBy(x => groupProperties[i].GetValue(x.Group, null));
  589. }
  590. orderingSerialNoList = orderingSerialNoList.ThenBy(x => x.SerialNo);
  591. serialNoList = orderingSerialNoList.ToList();
  592. }
  593. string lastStartSerialNo = "";
  594. foreach (var serialNo in serialNoList)
  595. {
  596. if (!serialNo.IsEnd)
  597. {
  598. lastStartSerialNo = serialNo.SerialNo;
  599. }
  600. else
  601. {
  602. T item = (T)typeof(T).Assembly.CreateInstance(typeof(T).FullName);
  603. //AutoMapper.Mapper.Map(item, serialNo.Group);
  604. foreach (var property in groupProperties)
  605. {
  606. allProperties.Where(x => x.Name == property.Name).First().SetValue(item, property.GetValue(serialNo.Group, null), null);
  607. }
  608. allProperties.Where(x => x.Name == serialNoStartColumnName).First().SetValue(item, lastStartSerialNo, null);
  609. allProperties.Where(x => x.Name == serialNoEndColumnName).First().SetValue(item, serialNo.SerialNo, null);
  610. if (qtyColumnName != "")
  611. {
  612. allProperties.Where(x => x.Name == qtyColumnName).First().SetValue(item, CardSerialNoContainNum(lastStartSerialNo, serialNo.SerialNo), null);
  613. }
  614. result.Add(item);
  615. }
  616. }
  617. return result;
  618. }
  619. public static string GetMaxSerialNo(string serialNo1, string serialNo2)
  620. {
  621. return CompareGreater(serialNo1, serialNo2) ? serialNo2 : serialNo1;
  622. }
  623. public static string GetMinSerialNo(string serialNo1, string serialNo2)
  624. {
  625. return CompareGreater(serialNo1, serialNo2) ? serialNo1 : serialNo2;
  626. }
  627. /// <summary>
  628. /// 获取两个字符串的相同开头
  629. /// </summary>
  630. /// <param name="string1"></param>
  631. /// <param name="string2"></param>
  632. /// <returns></returns>
  633. public static string GetSameStart(string string1, string string2)
  634. {
  635. int i;
  636. int minLength;
  637. int differentIndex = -1;
  638. char[] char1, char2;
  639. if (string1 == "" || string2 == "")
  640. { return ""; }
  641. if (string1.Length > string2.Length)
  642. { minLength = string2.Length; }
  643. else
  644. { minLength = string1.Length; }
  645. char1 = string1.ToCharArray();
  646. char2 = string2.ToCharArray();
  647. for (i = 0; i < minLength; i++)
  648. {
  649. if (char1[i] != char2[i])
  650. {
  651. differentIndex = i;
  652. break;
  653. }
  654. }
  655. if (differentIndex != -1)
  656. { return string1.Substring(0, differentIndex); }
  657. else
  658. { return string1.Substring(0, minLength); }
  659. }
  660. public static string TrimStart(string source, string trimString)
  661. {
  662. int i;
  663. if (source == "" || trimString == "")
  664. { return ""; }
  665. if (trimString.Length > source.Length)
  666. {
  667. throw (new Exception("搜索的字符串长度超出源字符串范围。"));
  668. }
  669. if (!source.StartsWith(trimString))
  670. { return source; }
  671. return source.Substring(trimString.Length, source.Length - trimString.Length);
  672. }
  673. public static IList<SerialNoSegment> SerialNoDecrease(this IList<SerialNoSegment> sourceList, IList<SerialNoSegment> decreasorList)
  674. {
  675. int i, j, k;
  676. IList<SerialNoSegment> resultList = null;
  677. foreach (var source in sourceList.OrderBy(x => x.SerialNoStart))
  678. {
  679. string startSerialNo = source.SerialNoStart;
  680. string endSerialNo = source.SerialNoEnd;
  681. foreach (var decreasor in decreasorList.OrderBy(x => x.SerialNoStart))
  682. {
  683. string decreaseStartSerialNo = decreasor.SerialNoStart;
  684. string decreaseEndSerialNo = decreasor.SerialNoEnd;
  685. try
  686. {
  687. if (decreaseStartSerialNo == "0" || decreaseEndSerialNo == "0")
  688. {
  689. continue;
  690. }
  691. if (startSerialNo.Length != decreaseStartSerialNo.Length)
  692. {
  693. continue;
  694. }
  695. string sameStart = GetSameStart(startSerialNo, decreaseStartSerialNo);
  696. string sameEnd = GetSameStart(endSerialNo, decreaseEndSerialNo);
  697. string sameAll = GetSameStart(sameStart, sameEnd);
  698. if (sameStart.Length == startSerialNo.Length && sameEnd.Length == endSerialNo.Length)
  699. {
  700. break;
  701. }
  702. if (!IsInt(TrimStart(startSerialNo, sameAll)) || !IsInt(TrimStart(decreaseStartSerialNo, sameAll))
  703. || !IsInt(TrimStart(endSerialNo, sameAll)) || !IsInt(TrimStart(decreaseEndSerialNo, sameAll)))
  704. {
  705. continue;
  706. }
  707. int intStartSerialNo, intEndSerialNo, intDecreaseStartSerialNo, intDecreaseEndSerialNo;
  708. intStartSerialNo = Convert.ToInt32(TrimStart(startSerialNo, sameAll));
  709. intEndSerialNo = Convert.ToInt32(TrimStart(endSerialNo, sameAll));
  710. intDecreaseStartSerialNo = Convert.ToInt32(TrimStart(decreaseStartSerialNo, sameAll));
  711. intDecreaseEndSerialNo = Convert.ToInt32(TrimStart(decreaseEndSerialNo, sameAll));
  712. if (!(intStartSerialNo <= intDecreaseEndSerialNo && intEndSerialNo >= intDecreaseStartSerialNo))
  713. {
  714. continue;
  715. }
  716. if (intStartSerialNo >= intDecreaseStartSerialNo && intEndSerialNo <= intDecreaseEndSerialNo)
  717. {
  718. break;
  719. }
  720. if (intStartSerialNo < intDecreaseStartSerialNo)
  721. {
  722. resultList.Add(new SerialNoSegment { SerialNoStart = startSerialNo, SerialNoEnd = CardSerialNoAddNum(decreaseStartSerialNo, -1) });
  723. }
  724. if (intEndSerialNo > intDecreaseEndSerialNo)
  725. {
  726. startSerialNo = CardSerialNoAddNum(decreaseEndSerialNo, 1);
  727. resultList.Add(new SerialNoSegment { SerialNoStart = startSerialNo, SerialNoEnd = endSerialNo });
  728. }
  729. else
  730. {
  731. startSerialNo = "0";
  732. endSerialNo = "0";
  733. }
  734. }
  735. catch (Exception ex)
  736. {
  737. throw (ex);
  738. }
  739. }
  740. }
  741. return resultList;
  742. }
  743. }
  744. public class SerialNoSegment
  745. {
  746. public string SerialNoStart { get; set; }
  747. public string SerialNoEnd { get; set; }
  748. }
  749. public class OperateSerialNoException : Exception
  750. {
  751. public OperateSerialNoException(string message)
  752. : base(message)
  753. { }
  754. public OperateSerialNoException(string message, Exception ex)
  755. : base(message, ex)
  756. { }
  757. }
  758. }