首先需要说明该部分代码虽然经过个人测试,也使用扫描枪测试,但本人不保证代码完全正确
其次代码没有遵循“先预定义长度后非定长”的原则,但遵循了非预定义长度字符串后都加入FNC1分隔符
最后虽然此部分代码遵循了 GBT 16986-2009 商品条码 应用标识符标准,但实际并未完全遵循,仅遵循了标识符长度和输入字母原则
补充:此部分代码用到了前面的Code128Auto的生成编码代码,所以将部分代码做了调整,以下是相关的代码
Code128
/// <summary> /// Code128基础相关类 /// </summary> internal static class Code128 { /* * 128 尺寸要求 * 最小模块宽度 x 最大1.016mm,最小0.250mm 一个系统中的x应为一恒定值 标准是1mm,放大系数0.25~1.2 * 左右侧空白区最小宽度为 10x * 条高通常为32mm,实际可以根据具体要求 * * 最大物理长度不应超过 165mm,可编码的最大数据字符数为48,其中包括应用标识符和作为分隔符使用的FNC1字符,但不包括辅助字符和校验符 * * AI中FNC1同样作为分隔符使用 * * ASCII * 0~31 StartA 专有 * 96~127 StartB 专有 * * EAN128不使用空格(ASCII码32) */ /// <summary> /// Code128条空排列集合,1代表条b,0代表空s,Index对应符号字符值S /// </summary> internal static readonly List<string> BSList = new List<string>() { "212222" , "222122" , "222221" , "121223" , "121322" , "131222" , "122213" , "122312" , "132212" , "221213" , "221312" , "231212" , "112232" , "122132" , "122231" , "113222" , "123122" , "123221" , "223211" , "221132" , "221231" , "213212" , "223112" , "312131" , "311222" , "321122" , "321221" , "312212" , "322112" , "322211" , "212123" , "212321" , "232121" , "111323" , "131123" , "131321" , "112313" , "132113" , "132311" , "211313" , "231113" , "231311" , "112133" , "112331" , "132131" , "113123" , "113321" , "133121" , "313121" , "211331" , "231131" , "213113" , "213311" , "213131" , "311123" , "311321" , "331121" , "312113" , "312311" , "332111" , "314111" , "221411" , "431111" , "111224" , "111422" , "121124" , "121421" , "141122" , "141221" , "112214" , "112412" , "122114" , "122411" , "142112" , "142211" , "241211" , "221114" , "413111" , "241112" , "134111" , "111242" , "121142" , "121241" , "114212" , "124112" , "124211" , "411212" , "421112" , "421211" , "212141" , "214121" , "412121" , "111143" , "111341" , "131141" , "114113" , "114311" , "411113" , "411311" , "113141" , "114131" , "311141" , "411131" , "211412" , "211214" , "211232" , "2331112" }; #region 条空排列集合 //{ // "11011001100" , "11001101100" , "11001100110" , "10010011000" , "10010001100" , // "10001001100" , "10011001000" , "10011000100" , "10001100100" , "11001001000" , // "11001000100" , "11000100100" , "10110011100" , "10011011100" , "10011001110" , // "10111001100" , "10011101100" , "10011100110" , "11001110010" , "11001011100" , // "11001001110" , "11011100100" , "11001110100" , "11101101110" , "11101001100" , // "11100101100" , "11100100110" , "11101100100" , "11100110100" , "11100110010" , // "11011011000" , "11011000110" , "11000110110" , "10100011000" , "10001011000" , // "10001000110" , "10110001000" , "10001101000" , "10001100010" , "11010001000" , // "11000101000" , "11000100010" , "10110111000" , "10110001110" , "10001101110" , // "10111011000" , "10111000110" , "10001110110" , "11101110110" , "11010001110" , // "11000101110" , "11011101000" , "11011100010" , "11011101110" , "11101011000" , // "11101000110" , "11100010110" , "11101101000" , "11101100010" , "11100011010" , // "11101111010" , "11001000010" , "11110001010" , "10100110000" , "10100001100" , // "10010110000" , "10010000110" , "10000101100" , "10000100110" , "10110010000" , // "10110000100" , "10011010000" , "10011000010" , "10000110100" , "10000110010" , // "11000010010" , "11001010000" , "11110111010" , "11000010100" , "10001111010" , // "10100111100" , "10010111100" , "10010011110" , "10111100100" , "10011110100" , // "10011110010" , "11110100100" , "11110010100" , "11110010010" , "11011011110" , // "11011110110" , "11110110110" , "10101111000" , "10100011110" , "10001011110" , // "10111101000" , "10111100010" , "11110101000" , "11110100010" , "10111011110" , // "10111101110" , "11101011110" , "11110101110" , "11010000100" , "11010010000" , // "11010011100" , "1100011101011" //}; #endregion internal const byte FNC3_AB = 96, FNC2_AB = 97, SHIFT_AB = 98, CODEC_AB = 99, CODEB_AC = 100, CODEA_BC = 101; internal const byte FNC4_A = 101, FNC4_B = 100; internal const byte FNC1 = 102, StartA = 103, StartB = 104, StartC = 105; internal const byte Stop = 106; /// <summary> /// 获取字符在字符集A中对应的符号字符值S /// </summary> /// <param name="c"></param> /// <returns></returns> internal static byte GetSIndexFromA(char c) { byte sIndex = (byte)c; //字符集A中 符号字符值S 若ASCII<32,则 S=ASCII+64 ,若95>=ASCII>=32,则S=ASCII-32 if (sIndex < 32) { sIndex += 64; } else if (sIndex < 96) { sIndex -= 32; } else { throw new NotImplementedException(); } return sIndex; } /// <summary> /// 获取字符在字符集B中对应的符号字符值S /// </summary> /// <param name="c"></param> /// <returns></returns> internal static byte GetSIndexFromB(char c) { byte sIndex = (byte)c; if (sIndex > 31 && sIndex < 128) { sIndex -= 32;//字符集B中ASCII码 减去32后就等于符号字符值 } else { throw new NotImplementedException(); } return sIndex; } internal static byte GetSIndex(CharacterSet characterSet, char c) { switch (characterSet) { case CharacterSet.A: return GetSIndexFromA(c); case CharacterSet.B: return GetSIndexFromB(c); default: throw new NotImplementedException(); } } /// <summary> /// 判断指定字符是否仅属于指定字符集 /// </summary> /// <param name="characterSet"></param> /// <param name="c"></param> /// <returns></returns> internal static bool CharOnlyBelongsTo(CharacterSet characterSet, char c) { switch (characterSet) { case CharacterSet.A: return (byte)c < 32; case CharacterSet.B: return (byte)c > 95 && (byte)c < 128; default: throw new NotImplementedException(); } } /// <summary> /// 判断指定字符是否不属于指定字符集 /// </summary> /// <param name="characterSet"></param> /// <param name="c"></param> /// <returns></returns> internal static bool CharNotBelongsTo(CharacterSet characterSet, char c) { switch (characterSet) { case CharacterSet.A: return (byte)c > 95; case CharacterSet.B: return (byte)c < 32 && (byte)c > 127; default: throw new NotImplementedException(); } } /// <summary> /// 当编码转换时,获取相应的切换符对应的符号字符值 /// </summary> /// <param name="newCharacterSet"></param> /// <returns></returns> internal static byte GetCodeXIndex(CharacterSet newCharacterSet) { switch (newCharacterSet) { case CharacterSet.A: return CODEA_BC; case CharacterSet.B: return CODEB_AC; default: return CODEC_AB; } } /// <summary> /// 获取转换后的字符集 /// </summary> /// <param name="characterSet"></param> /// <returns></returns> internal static CharacterSet GetShiftCharacterSet(CharacterSet characterSet) { switch (characterSet) { case CharacterSet.A: return CharacterSet.B; case CharacterSet.B: return CharacterSet.A; default: throw new NotImplementedException(); } } /// <summary> /// 获取指定字符串应该采用的起始符对应的符号字符值 /// </summary> /// <param name="data"></param> /// <returns></returns> internal static byte GetStartIndex(string data, out CharacterSet startCharacterSet) { startCharacterSet = GetCharacterSet(data, 0); switch (startCharacterSet) { case CharacterSet.A: return StartA; case CharacterSet.B: return StartB; default: return StartC; } } /// <summary> /// 获取应采用的字符集 /// </summary> /// <param name="data"></param> /// <param name="startIndex">判断开始位置</param> /// <returns></returns> internal static CharacterSet GetCharacterSet(string data, int startIndex) { CharacterSet returnSet = CharacterSet.B; if (Regex.IsMatch(data.Substring(startIndex), @"^\d{4,}")) { returnSet = CharacterSet.C; } else { byte byteC = GetProprietaryChar(data, startIndex); returnSet = byteC < 32 ? CharacterSet.A : CharacterSet.B; } return returnSet; } /// <summary> /// 从指定位置开始,返回第一个大于95(并且小于128)或小于32的字符对应的值 /// </summary> /// <param name="data"></param> /// <param name="startIndex"></param> /// <returns>如果没有任何字符匹配,则返回255</returns> internal static byte GetProprietaryChar(string data, int startIndex) { byte returnByte = byte.MaxValue; for (int i = startIndex; i < data.Length; i++) { byte byteC = (byte)data[i]; if (byteC < 32 || byteC > 95 && byteC < 128) { returnByte = byteC; break; } } return returnByte; } /// <summary> /// 获取字符串从指定位置开始连续出现数字的个数 /// </summary> /// <param name="data"></param> /// <param name="startIndex"></param> /// <returns></returns> internal static int GetDigitLength(string data, int startIndex) { int digitLength = data.Length - startIndex;//默认设定从起始位置开始至最后都是数字 for (int i = startIndex; i < data.Length; i++) { if (!char.IsDigit(data[i])) { digitLength = i - startIndex; break; } } return digitLength; } /// <summary> /// 通用方法 /// </summary> /// <param name="tempBuilder"></param> /// <param name="sIndex"></param> /// <param name="nowWeight"></param> /// <param name="checkNum"></param> internal static void EncodingCommon(StringBuilder tempBuilder, byte sIndex, ref int nowWeight, ref int checkNum) { tempBuilder.Append(BSList[sIndex]); checkNum += nowWeight * sIndex; nowWeight++; } /// <summary> /// 获取原始数据对应的编码后数据(不包括起始符、特殊符(EAN128时)、检验符、终止符) /// </summary> /// <param name="rawData">编码对应的原始数据</param> /// <param name="tempBuilder">编码数据容器</param> /// <param name="nowCharacterSet">当前字符集</param> /// <param name="i">字符串索引</param> /// <param name="nowWeight">当前权值</param> /// <param name="checkNum">当前检验值总和</param> internal static void GetEncodedData(string rawData, StringBuilder tempBuilder, ref CharacterSet nowCharacterSet, ref int i, ref int nowWeight, ref int checkNum) {//因为可能存在字符集C,所以i与nowWeight可能存在不一致关系,所以要分别定义 byte sIndex; switch (nowCharacterSet) { case CharacterSet.A: case CharacterSet.B: for (; i < rawData.Length; i++) { if (char.IsDigit(rawData[i])) { //数字 int digitLength = GetDigitLength(rawData, i); if (digitLength >= 4) { //转入CodeC if (digitLength % 2 != 0) {//奇数位数字,在第一个数字之后插入CodeC字符 sIndex = GetSIndex(nowCharacterSet, (rawData[i])); EncodingCommon(tempBuilder, sIndex, ref nowWeight, ref checkNum); i++; } nowCharacterSet = CharacterSet.C; sIndex = GetCodeXIndex(nowCharacterSet);//插入CodeC切换字符 EncodingCommon(tempBuilder, sIndex, ref nowWeight, ref checkNum); GetEncodedData(rawData, tempBuilder, ref nowCharacterSet, ref i, ref nowWeight, ref checkNum); return; } else { //如果小于4位数字,则直接内部循环结束 for (int j = 0; j < digitLength; j++) { sIndex = GetSIndex(nowCharacterSet, (rawData[i])); EncodingCommon(tempBuilder, sIndex, ref nowWeight, ref checkNum); i++; } i--;//因为上面循环结束后继续外部循环会导致i多加了1,所以要减去1 continue; } } else if (CharNotBelongsTo(nowCharacterSet, rawData[i])) {//当前字符不属于目前的字符集 byte tempByte = GetProprietaryChar(rawData, i + 1);//获取当前字符后第一个属于A,或B的字符集 CharacterSet tempCharacterSet = GetShiftCharacterSet(nowCharacterSet); if (tempByte != byte.MaxValue && CharOnlyBelongsTo(nowCharacterSet, (char)tempByte)) { //加入转换符 sIndex = SHIFT_AB; EncodingCommon(tempBuilder, sIndex, ref nowWeight, ref checkNum); sIndex = GetSIndex(tempCharacterSet, rawData[i]); EncodingCommon(tempBuilder, sIndex, ref nowWeight, ref checkNum); continue; } else { //加入切换符 nowCharacterSet = tempCharacterSet; sIndex = GetCodeXIndex(nowCharacterSet); EncodingCommon(tempBuilder, sIndex, ref nowWeight, ref checkNum); GetEncodedData(rawData, tempBuilder, ref nowCharacterSet, ref i, ref nowWeight, ref checkNum); return; } } else { sIndex = GetSIndex(nowCharacterSet, rawData[i]); EncodingCommon(tempBuilder, sIndex, ref nowWeight, ref checkNum); } } break; default: for (; i < rawData.Length; i += 2) { if (i != rawData.Length - 1 && char.IsDigit(rawData, i) && char.IsDigit(rawData, i + 1)) { sIndex = byte.Parse(rawData.Substring(i, 2)); EncodingCommon(tempBuilder, sIndex, ref nowWeight, ref checkNum); } else { nowCharacterSet = GetCharacterSet(rawData, i); //插入转换字符 sIndex = GetCodeXIndex(nowCharacterSet); EncodingCommon(tempBuilder, sIndex, ref nowWeight, ref checkNum); GetEncodedData(rawData, tempBuilder, ref nowCharacterSet, ref i, ref nowWeight, ref checkNum); return; } } break; } } } /// <summary> /// Code128字符集 /// </summary> internal enum CharacterSet { A, B, C }
AI相关
/// <summary> /// 商品应用标识符标准 GBT 16986-2009 /// </summary> internal static class AI { /// <summary> /// GBT 16986-2009 定义的应用标识符集合 /// </summary> public static readonly List<ApplicationIdentifier> AIList = new List<ApplicationIdentifier>() { //20系列货运包装箱代码 new ApplicationIdentifier("00", new List<DataFormat>(){ new DataFormat(new byte[]{18})}), //01全球贸易项目代码 new ApplicationIdentifier("01", new List<DataFormat>(){ new DataFormat(new byte[]{14})}), //02物流单元内贸易项目的GTIN new ApplicationIdentifier("02", new List<DataFormat>(){ new DataFormat(new byte[]{14})}), //10批号 new ApplicationIdentifier("10", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,20})}), //11生产日期YYMMDD new ApplicationIdentifier("11", new List<DataFormat>(){ new DataFormat(new byte[]{6})}), //12付款截止日期YYMMDD new ApplicationIdentifier("12", new List<DataFormat>(){ new DataFormat(new byte[]{6})}), //13包装日期YYMMDD new ApplicationIdentifier("13", new List<DataFormat>(){ new DataFormat(new byte[]{6})}), //15保质期YYMMDD new ApplicationIdentifier("15", new List<DataFormat>(){ new DataFormat(new byte[]{6})}), //17有效期YYMMDD new ApplicationIdentifier("17", new List<DataFormat>(){ new DataFormat(new byte[]{6})}), //20产品变体 new ApplicationIdentifier("20", new List<DataFormat>(){ new DataFormat(new byte[]{2})}), //21系列号 new ApplicationIdentifier("21", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,20})}), //22医疗卫生行业产品二级数据 new ApplicationIdentifier("22", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,29})}), //240附加产品标识 new ApplicationIdentifier("240", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}), //241客户方代码 new ApplicationIdentifier("241", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}), //242定制产品代码 new ApplicationIdentifier("242", new List<DataFormat>(){ new DataFormat(new byte[]{1,6})}), //250二级系列号 new ApplicationIdentifier("250", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}), //251源实体参考代码 new ApplicationIdentifier("251", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}), //253全球文件/单证类型代码 new ApplicationIdentifier("253", new List<DataFormat>(){ new DataFormat(new byte[]{13}),new DataFormat(new byte[]{1,17})}), //254GLN扩展部分代码 new ApplicationIdentifier("254", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,20})}), //30可变数量 new ApplicationIdentifier("30", new List<DataFormat>(){ new DataFormat(new byte[]{1,8})}), //31nn 贸易与物流量度 new ApplicationIdentifier("31", 4, new List<DataFormat>(){ new DataFormat(new byte[]{6})}), //32nn 贸易与物流量度 new ApplicationIdentifier("32", 4, new List<DataFormat>(){ new DataFormat(new byte[]{6})}), //33nn 贸易与物流量度 new ApplicationIdentifier("33", 4, new List<DataFormat>(){ new DataFormat(new byte[]{6})}), //34nn 贸易与物流量度 new ApplicationIdentifier("34", 4, new List<DataFormat>(){ new DataFormat(new byte[]{6})}), //35nn 贸易与物流量度 new ApplicationIdentifier("35", 4, new List<DataFormat>(){ new DataFormat(new byte[]{6})}), //36nn 贸易与物流量度 new ApplicationIdentifier("36", 4, new List<DataFormat>(){ new DataFormat(new byte[]{6})}), //37物流单元内贸易项目数量 new ApplicationIdentifier("37", new List<DataFormat>(){ new DataFormat(new byte[]{1,8})}), //390n单一货币区内应付款金额 new ApplicationIdentifier("390", 4, new List<DataFormat>(){ new DataFormat(new byte[]{1,15})}), //391n具有ISO货币代码的应付款金额 new ApplicationIdentifier("391", 4, new List<DataFormat>(){ new DataFormat(new byte[]{3}),new DataFormat(new byte[]{1,15})}), //392n单一货币区内变量贸易项目应付款金额 new ApplicationIdentifier("392", 4, new List<DataFormat>(){ new DataFormat(new byte[]{1,15})}), //393n具有ISO货币代码的变量贸易项目应付款金额 new ApplicationIdentifier("393", 4, new List<DataFormat>(){ new DataFormat(new byte[]{3}),new DataFormat(new byte[]{1,15})}), //400客户订购单代码 new ApplicationIdentifier("400", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}), //401货物托运代码 new ApplicationIdentifier("401", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}), //402 装运标识代码 new ApplicationIdentifier("402", new List<DataFormat>(){ new DataFormat(new byte[]{17})}), //403路径代码 new ApplicationIdentifier("403", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}), //410 交货地全球位置码 new ApplicationIdentifier("410", new List<DataFormat>(){ new DataFormat(new byte[]{13})}), //411 受票方全球位置码 new ApplicationIdentifier("411", new List<DataFormat>(){ new DataFormat(new byte[]{13})}), //412 最终目的地全球位置码 new ApplicationIdentifier("412", new List<DataFormat>(){ new DataFormat(new byte[]{13})}), //413 交货地全球位置码 new ApplicationIdentifier("413", new List<DataFormat>(){ new DataFormat(new byte[]{13})}), //414 标志物理位置的全球位置码 new ApplicationIdentifier("414", new List<DataFormat>(){ new DataFormat(new byte[]{13})}), //415 开票方全球位置码 new ApplicationIdentifier("415", new List<DataFormat>(){ new DataFormat(new byte[]{13})}), //420 同一邮政行政区域内交货地邮政编码 new ApplicationIdentifier("420", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}), //421 具有3位ISO国家(或地区)代码的交货地邮政编码 new ApplicationIdentifier("421", new List<DataFormat>(){ new DataFormat(new byte[]{3}),new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,9})}), //422 贸易项目原产国(或地区) new ApplicationIdentifier("422", new List<DataFormat>(){ new DataFormat(new byte[]{3})}), //423 贸易项目初始加工国(或地区) new ApplicationIdentifier("423", new List<DataFormat>(){ new DataFormat(new byte[]{3}),new DataFormat(new byte[]{1,12})}), //424 贸易项目加工国(或地区) new ApplicationIdentifier("424", new List<DataFormat>(){ new DataFormat(new byte[]{3})}), //425 贸易项目拆分国(或地区) new ApplicationIdentifier("425", new List<DataFormat>(){ new DataFormat(new byte[]{3})}), //426 全程加工贸易项目的国家(或地区) new ApplicationIdentifier("426", new List<DataFormat>(){ new DataFormat(new byte[]{3})}), //7001 北约物资代码 new ApplicationIdentifier("7001", new List<DataFormat>(){ new DataFormat(new byte[]{13})}), //7002 UN/ECE胴体肉与分割品分类 new ApplicationIdentifier("7002", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}), //7003 产品的有效日期和时间 new ApplicationIdentifier("7003", new List<DataFormat>(){ new DataFormat(new byte[]{8}),new DataFormat(new byte[]{1,2})}), //703s 具有3位ISO国家(或地区)代码的加工者核准号码 new ApplicationIdentifier("703", new List<DataFormat>(){ new DataFormat(new byte[]{3}),new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,27})}), //8001 卷装产品 new ApplicationIdentifier("8001", new List<DataFormat>(){ new DataFormat(new byte[]{14})}), //8002 蜂窝移动电话标识符 new ApplicationIdentifier("8002", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,20})}), //8003 全球可回收资产标识符 new ApplicationIdentifier("8003", new List<DataFormat>(){ new DataFormat(new byte[]{14}),new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,16})}), //8004 全球单个资产标识符 new ApplicationIdentifier("8004", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}), //8005 单价 new ApplicationIdentifier("8005", new List<DataFormat>(){ new DataFormat(new byte[]{6})}), //8006 贸易项目组件的标识符 new ApplicationIdentifier("8006", new List<DataFormat>(){ new DataFormat(new byte[]{14}),new DataFormat(new byte[]{2}),new DataFormat(new byte[]{2})}), //8007 国际银行账号代码 new ApplicationIdentifier("8007", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}), //8008 产品生产的日期和时间 new ApplicationIdentifier("8008", new List<DataFormat>(){ new DataFormat(new byte[]{8}),new DataFormat(new byte[]{1,4})}), //8018 全球服务关系代码 new ApplicationIdentifier("8018", new List<DataFormat>(){ new DataFormat(new byte[]{18})}), //8020 付款单代码 new ApplicationIdentifier("8020", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,25})}), //8100 GS1-128优惠券扩展代码-NSC+Offer Code new ApplicationIdentifier("8100", new List<DataFormat>(){ new DataFormat(new byte[]{1}),new DataFormat(new byte[]{5})}), //8101 GS1-128优惠券扩展代码-NSC+Offer Code + end of offer code new ApplicationIdentifier("8101", new List<DataFormat>(){ new DataFormat(new byte[]{1}),new DataFormat(new byte[]{5}),new DataFormat(new byte[]{4})}), //8102 GS1-128优惠券扩展代码-NSC new ApplicationIdentifier("8102", new List<DataFormat>(){ new DataFormat(new byte[]{1}),new DataFormat(new byte[]{1})}), //90 贸易伙伴之间相互约定的信息 new ApplicationIdentifier("90", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}), //91 公司内部信息 new ApplicationIdentifier("91", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}), //92 公司内部信息 new ApplicationIdentifier("92", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}), //93 公司内部信息 new ApplicationIdentifier("93", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}), //94 公司内部信息 new ApplicationIdentifier("94", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}), //95 公司内部信息 new ApplicationIdentifier("95", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}), //96 公司内部信息 new ApplicationIdentifier("96", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}), //97 公司内部信息 new ApplicationIdentifier("97", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}), //98 公司内部信息 new ApplicationIdentifier("98", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}), //99 公司内部信息 new ApplicationIdentifier("99", new List<DataFormat>(){ new DataFormat(AICharacter.a| AICharacter.n, new byte[]{1,30})}) }; /// <summary> /// 需要遵循的预定义长度的应用标识符及其对应的总长度 /// </summary> public static readonly List<KeyValuePair<string, byte>> PredefinedAILength = new List<KeyValuePair<string, byte>>() { new KeyValuePair<string,byte>("00",20),new KeyValuePair<string,byte>("01",16),new KeyValuePair<string,byte>("02",16),new KeyValuePair<string,byte>("03",16), new KeyValuePair<string,byte>("04",18),new KeyValuePair<string,byte>("11",8),new KeyValuePair<string,byte>("12",8),new KeyValuePair<string,byte>("13",8), new KeyValuePair<string,byte>("14",8),new KeyValuePair<string,byte>("15",8),new KeyValuePair<string,byte>("16",8),new KeyValuePair<string,byte>("17",8), new KeyValuePair<string,byte>("18",8),new KeyValuePair<string,byte>("19",8),new KeyValuePair<string,byte>("20",4),new KeyValuePair<string,byte>("31",10), new KeyValuePair<string,byte>("32",10),new KeyValuePair<string,byte>("33",10),new KeyValuePair<string,byte>("34",10),new KeyValuePair<string,byte>("35",10), new KeyValuePair<string,byte>("36",10),new KeyValuePair<string,byte>("41",16) }; /// <summary> /// 获取字符串对应的 第一个 商品应用标识 /// </summary> /// <param name="rawData"></param> /// <returns></returns> internal static ApplicationIdentifier GetAI(string rawData) { return AIList.Where(ai => rawData.StartsWith(ai.AI)).FirstOrDefault(); } /// <summary> /// 判断指定字符串是否是预定义长度应用标识符 /// </summary> /// <param name="data"></param> /// <returns></returns> internal static bool IsPredefinedAI(string data) { KeyValuePair<string, byte> temp = PredefinedAILength.Where(ai => data.StartsWith(ai.Key) && data.Length == ai.Value).FirstOrDefault(); return !string.IsNullOrEmpty(temp.Key); } /// <summary> /// 判断指定字符串是否是符合指定应用标识规范 /// </summary> /// <param name="ai"></param> /// <param name="aiStr"></param> /// <returns></returns> internal static bool IsRight(ApplicationIdentifier ai, string aiStr) { //标识符部分,字符串必须以相同的AI开头 if (!aiStr.StartsWith(ai.AI) || aiStr.Length > ai.MaxLength || aiStr.Length < ai.MinLength) { return false; } //如果AILength与ai对应的AI长度不一致时,还需检验后续几个字符是否是数字 for (int i = ai.AI.Length; i < ai.AILength; i++) { if (!char.IsDigit(aiStr[i])) { return false; } } int ptr = ai.AILength; for (int i = 0; i < ai.DataWithoutAI.Count; i++) { DataFormat df = ai.DataWithoutAI[i]; for (int j = 0; j < df.Length[df.Length.Length - 1]; j++) { if ((df.Character == AICharacter.n && !char.IsDigit(aiStr[ptr])) || (byte)aiStr[ptr] < 33 || (byte)aiStr[ptr] > 126) { return false; } ptr++; if (ptr >= aiStr.Length) { break; } } } return true; } } /// <summary> /// 商品标识符的数据类型范围 /// </summary> [Flags] internal enum AICharacter { /// <summary> /// 数字 /// </summary> n = 1, /// <summary> /// 字母 /// </summary> a = 2 } /// <summary> /// 商品应用标识 /// </summary> internal sealed class ApplicationIdentifier { private bool _isFixedLength; private string _ai; private byte _aiLength; private List<DataFormat> _dataWithoutAI; private byte _minLength; private byte _maxLength; public ApplicationIdentifier(string ai, List<DataFormat> dataWithoutAI) : this(ai, (byte)ai.Length, dataWithoutAI) { } public ApplicationIdentifier(string ai, byte aiLength, List<DataFormat> dataWithoutAI) { this._ai = ai; this._aiLength = aiLength; this._dataWithoutAI = dataWithoutAI; this._minLength = aiLength; this._maxLength = aiLength; for (int i = 0; i < this._dataWithoutAI.Count; i++) { byte[] temp = this._dataWithoutAI[i].Length; this._minLength += temp[0]; this._maxLength += temp[temp.Length - 1]; } this._isFixedLength = this._minLength == this._maxLength; } /// <summary> /// 商品应用标识符 /// </summary> public string AI { get { return this._ai; } } /// <summary> /// 标识符长度 /// </summary> public byte AILength { get { return this._aiLength; } } /// <summary> /// 排除标识符后字符串的数据格式 /// </summary> public List<DataFormat> DataWithoutAI { get { return this._dataWithoutAI; } } /// <summary> /// 是否定长 /// </summary> public bool IsFixedLength { get { return this._isFixedLength; } } /// <summary> /// 获取该商品应用标识允许的最小长度(包含AI) /// </summary> /// <returns></returns> public byte MinLength { get { return this._minLength; } } /// <summary> /// 获取该商品应用标识允许的最大长度(包含AI) /// </summary> /// <returns></returns> public byte MaxLength { get { return this._maxLength; } } } /// <summary> /// 数据格式 /// </summary> internal sealed class DataFormat { private AICharacter _character; private byte[] _length; /// <summary> /// 默认数据格式为数字 /// </summary> /// <param name="length"></param> public DataFormat(byte[] length) : this(AICharacter.n, length) { } public DataFormat(AICharacter character, byte[] length) { this._character = character; this._length = length; } /// <summary> /// 数据类型 /// </summary> public AICharacter Character { get { return this._character; } } /// <summary> /// 数据长度,数组长度为1时表示定长 /// </summary> public byte[] Length { get { return this._length; } } }
GS1-128
/// <summary> /// GS1-128(UCC/EAN128)条形码,遵循标准GB/T 16986-2009 /// </summary> public class GS1_128 : absCode128 { private List<string> _aiList = new List<string>();//rawData分割后符合商品应用标识规范的字符串集合 /// <summary> /// GS1-128(UCC/EAN128)条形码,非定长标识符后面必须跟空格,定长标识符带不带无所谓 /// </summary> /// <param name="rawData">包含ASCII码表32~126,其中32对应的空格sp用来通知生成FNC1分割符</param> public GS1_128(string rawData) : base(rawData) { } /// <summary> /// 对应的ASCII码范围为32~126,其中32对应的空格sp用来通知生成FNC1分割符 /// </summary> /// <returns></returns> protected override bool RawDataCheck() { this._presentationData = string.Empty; string[] tempArray = this._rawData.Split((char)32);//以空格为分隔符将字符串进行分割 foreach (string ts in tempArray) { int ptr = 0; do { string tempStr; ApplicationIdentifier ai = AI.GetAI(ts.Substring(ptr)); int residuelength = ts.Length - ptr;//剩余字符串长度 if (ai == null || residuelength < ai.MinLength || (!ai.IsFixedLength && residuelength > ai.MaxLength)) {//第三个判定条件:因为不定长,而且经过空格分割,所以此时如果出现剩余字符串长度超出标识符最大长度规定,则认为错误 return false; } else { int length = Math.Min(ai.MaxLength, residuelength); tempStr = ts.Substring(ptr, length); ptr += length; } if (!AI.IsRight(ai, tempStr)) { return false; } //展示数据加上括号 this._presentationData += string.Format("({0}){1}", tempStr.Substring(0, ai.AILength), tempStr.Substring(ai.AILength)); #region 修改为遵循预定义长度的AI后面才不加上FNC1,而不是实际定长的就不加上FNC1 //if (!ai.IsFixedLength) //{ // tempStr += (char)32;//为不定长AI加上空格,以便生成条形码时确认需要在此部分后面加入分隔符FNC1 //} #endregion this._aiList.Add(tempStr); } while (ptr < ts.Length); } //是否要将_aiList进行排序,将预定长的放在前面以符合 先定长后变长 原则 //如果修改,则需将展示数据部分重新处理 return true; } protected override string GetEncodedData() { StringBuilder tempBuilder = new StringBuilder(); CharacterSet nowCharacterSet; //校验字符 int checkNum = Code128.GetStartIndex(this._aiList[0], out nowCharacterSet); tempBuilder.Append(Code128.BSList[checkNum]);//加上起始符 tempBuilder.Append(Code128.BSList[Code128.FNC1]);//加上第一个FNC1表示当前是GS1-128 checkNum += Code128.FNC1; int nowWeight = 2;//当前权值 for (int i = 0; i < this._aiList.Count; i++) { string tempStr = this._aiList[i]; int nowIndex = 0; #region 修改为遵循预定义长度的AI后面才不加上FNC1,而不是实际定长的就不加上FNC1 //bool isEndWithSP = tempStr[tempStr.Length - 1] == (char)32; //if (isEndWithSP) //{ // tempStr = tempStr.Substring(0, tempStr.Length - 1); //} #endregion Code128.GetEncodedData(tempStr, tempBuilder, ref nowCharacterSet, ref nowIndex, ref nowWeight, ref checkNum); #region 修改为遵循预定义长度的AI后面才不加上FNC1,而不是实际定长的就不加上FNC1 //if (isEndWithSP && i != this._aiList.Count - 1) //{ // //非定长标识符后面加上FNC1,此时FNC1作为分隔符存在 // Code128.EncodingCommon(tempBuilder, Code128.FNC1, ref nowWeight, ref checkNum); //} #endregion if (!AI.IsPredefinedAI(tempStr) && i != this._aiList.Count - 1) { //非预定长标识符后面加上FNC1,此时FNC1作为分隔符存在 Code128.EncodingCommon(tempBuilder, Code128.FNC1, ref nowWeight, ref checkNum); } } checkNum %= 103; tempBuilder.Append(Code128.BSList[checkNum]);//加上校验符 tempBuilder.Append(Code128.BSList[Code128.Stop]);//加上结束符 return tempBuilder.ToString(); } }