C#条形码⽣成(六)----GS1-128条形码
⾸先需要说明该部分代码虽然经过个⼈测试,也使⽤扫描测试,但本⼈不保证代码完全正确
其次代码没有遵循“先预定义长度后⾮定长”的原则,但遵循了⾮预定义长度字符串后都加⼊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" ,
//    "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)
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>
/// 获取转换后的字符集
/// </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>weight可不可数
/// 通⽤⽅法
/// </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 checkNu        {//因为可能存在字符集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)