EAN128或GS1-128解码c#

时间:2012-03-15 14:23:57

标签: c# regex decode

以下是EAN128的样本或新名称GS1-128条形码

  

01088888931021461712031510W1040190

我想将其解码为ais

  

(01)08888893102146
  (17)120315个
  (10)W1040190

但条形码可以像这样改变

  

1712031510W1040190
  (17)120315个
  (10)W1040190

是否有任何可能的方法来解决它与正则表达式或更好的方式

现在我正在尝试这个

public String AICodes(String pAI)
    {
        switch (pAI)
        {
            case "01":
                return "01\\d{14}";
            case "17":
                return "17\\d{6}";
            case "10":
                return "17\\d{6}10[a-zA-Z0-9|]{1,20}";
        }
        return String.Empty;
    }

private void GS1DataConvert(string pBarcode, string pBarfnc)
    {
       Match match = Regex.Match(pBarcode, AICodes(pBarfnc));
        if (match.Success)
        {
            MessageBox.Show(match.Groups[0].Value);
        }
    }

string barfnc = "01";

GS1DataConvert(barcode, barfnc);
barfnc = "17";
GS1DataConvert(barcode, barfnc);
barfnc = "10";
GS1DataConvert(barcode, barfnc);

4 个答案:

答案 0 :(得分:17)

这是我的解决方案。它有一个完整的AI清单,并支持一个组隔离器。我将此解决方案用于DATALOGIC PM9500扫描仪。因此,我不知道其他扫描仪的组分隔符或起始代码是否相同。 我根据目的对AIs 91至99进行了评论。长度可以由公司定义。

public static class EAN128Parser
{
    public enum DataType
    {
        Numeric,
        Alphanumeric
    }

    /// <summary>
    /// Information Class for an Application Identifier (AI)
    /// </summary>
    public class AII
    {
        public string AI { get; set; }
        public string Description { get; set; }
        public int LengthOfAI { get; set; }
        public DataType DataDescription { get; set; }
        public int LengthOfData { get; set; }
        public bool FNC1 { get; set; }

        public AII(string AI, string Description, int LengthOfAI, DataType DataDescription, int LengthOfData, bool FNC1)
        {
            this.AI = AI;
            this.Description = Description;
            this.LengthOfAI = LengthOfAI;
            this.DataDescription = DataDescription;
            this.LengthOfData = LengthOfData;
            this.FNC1 = FNC1;
        }

        public override string ToString()
        {
            return String.Format("{0} [{1}]", AI, Description);
        }
    }

    private static SortedDictionary<string, AII> aiiDict = new SortedDictionary<string, AII>();
    private static string[] aiis;
    private static int minLengthOfAI = 1;
    private static int maxLengthOfAI = 4;
    private static char groutSeperator = (char)29;
    private static string ean128StartCode = "]C1";
    private static bool hasCheckSum = true;

    public static bool HasCheckSum
    {
        get { return EAN128Parser.hasCheckSum; }
        set { EAN128Parser.hasCheckSum = value; }
    }

    public static char GroutSeperator
    {
        get { return EAN128Parser.groutSeperator; }
        set { EAN128Parser.groutSeperator = value; }
    }

    public static string EAN128StartCode
    {
        get { return EAN128Parser.ean128StartCode; }
        set { EAN128Parser.ean128StartCode = value; }
    }

    static EAN128Parser()
    {
        Add("00", "SerialShippingContainerCode", 2, DataType.Numeric, 18, false);
        Add("01", "EAN-NumberOfTradingUnit", 2, DataType.Numeric, 14, false);
        Add("02", "EAN-NumberOfTheWaresInTheShippingUnit", 2, DataType.Numeric, 14, false);
        Add("10", "Charge_Number", 2, DataType.Alphanumeric, 20, true);
        Add("11", "ProducerDate_JJMMDD", 2, DataType.Numeric, 6, false);
        Add("12", "DueDate_JJMMDD", 2, DataType.Numeric, 6, false);
        Add("13", "PackingDate_JJMMDD", 2, DataType.Numeric, 6, false);
        Add("15", "MinimumDurabilityDate_JJMMDD", 2, DataType.Numeric, 6, false);
        Add("17", "ExpiryDate_JJMMDD", 2, DataType.Numeric, 6, false);
        Add("20", "ProductModel", 2, DataType.Numeric, 2, false);
        Add("21", "SerialNumber", 2, DataType.Alphanumeric, 20, true);
        Add("22", "HIBCCNumber", 2, DataType.Alphanumeric, 29, false);
        Add("240", "PruductIdentificationOfProducer", 3, DataType.Alphanumeric, 30, true);
        Add("241", "CustomerPartsNumber", 3, DataType.Alphanumeric, 30, true);
        Add("250", "SerialNumberOfAIntegratedModule", 3, DataType.Alphanumeric, 30, true);
        Add("251", "ReferenceToTheBasisUnit", 3, DataType.Alphanumeric, 30, true);
        Add("252", "GlobalIdentifierSerialisedForTrade", 3, DataType.Numeric, 2, false);
        Add("30", "AmountInParts", 2, DataType.Numeric, 8, true);
        Add("310d", "NetWeight_Kilogram", 4, DataType.Numeric, 6, false);
        Add("311d", "Length_Meter", 4, DataType.Numeric, 6, false);
        Add("312d", "Width_Meter", 4, DataType.Numeric, 6, false);
        Add("313d", "Heigth_Meter", 4, DataType.Numeric, 6, false);
        Add("314d", "Surface_SquareMeter", 4, DataType.Numeric, 6, false);
        Add("315d", "NetVolume_Liters", 4, DataType.Numeric, 6, false);
        Add("316d", "NetVolume_CubicMeters", 4, DataType.Numeric, 6, false);
        Add("320d", "NetWeight_Pounds", 4, DataType.Numeric, 6, false);
        Add("321d", "Length_Inches", 4, DataType.Numeric, 6, false);
        Add("322d", "Length_Feet", 4, DataType.Numeric, 6, false);
        Add("323d", "Length_Yards", 4, DataType.Numeric, 6, false);
        Add("324d", "Width_Inches", 4, DataType.Numeric, 6, false);
        Add("325d", "Width_Feed", 4, DataType.Numeric, 6, false);
        Add("326d", "Width_Yards", 4, DataType.Numeric, 6, false);
        Add("327d", "Heigth_Inches", 4, DataType.Numeric, 6, false);
        Add("328d", "Heigth_Feed", 4, DataType.Numeric, 6, false);
        Add("329d", "Heigth_Yards", 4, DataType.Numeric, 6, false);
        Add("330d", "GrossWeight_Kilogram", 4, DataType.Numeric, 6, false);
        Add("331d", "Length_Meter", 4, DataType.Numeric, 6, false);
        Add("332d", "Width_Meter", 4, DataType.Numeric, 6, false);
        Add("333d", "Heigth_Meter", 4, DataType.Numeric, 6, false);
        Add("334d", "Surface_SquareMeter", 4, DataType.Numeric, 6, false);
        Add("335d", "GrossVolume_Liters", 4, DataType.Numeric, 6, false);
        Add("336d", "GrossVolume_CubicMeters", 4, DataType.Numeric, 6, false);
        Add("337d", "KilogramPerSquareMeter", 4, DataType.Numeric, 6, false);
        Add("340d", "GrossWeight_Pounds", 4, DataType.Numeric, 6, false);
        Add("341d", "Length_Inches", 4, DataType.Numeric, 6, false);
        Add("342d", "Length_Feet", 4, DataType.Numeric, 6, false);
        Add("343d", "Length_Yards", 4, DataType.Numeric, 6, false);
        Add("344d", "Width_Inches", 4, DataType.Numeric, 6, false);
        Add("345d", "Width_Feed", 4, DataType.Numeric, 6, false);
        Add("346d", "Width_Yards", 4, DataType.Numeric, 6, false);
        Add("347d", "Heigth_Inches", 4, DataType.Numeric, 6, false);
        Add("348d", "Heigth_Feed", 4, DataType.Numeric, 6, false);
        Add("349d", "Heigth_Yards", 4, DataType.Numeric, 6, false);
        Add("350d", "Surface_SquareInches", 4, DataType.Numeric, 6, false);
        Add("351d", "Surface_SquareFeet", 4, DataType.Numeric, 6, false);
        Add("352d", "Surface_SquareYards", 4, DataType.Numeric, 6, false);
        Add("353d", "Surface_SquareInches", 4, DataType.Numeric, 6, false);
        Add("354d", "Surface_SquareFeed", 4, DataType.Numeric, 6, false);
        Add("355d", "Surface_SquareYards", 4, DataType.Numeric, 6, false);
        Add("356d", "NetWeight_TroyOunces", 4, DataType.Numeric, 6, false);
        Add("357d", "NetVolume_Ounces", 4, DataType.Numeric, 6, false);
        Add("360d", "NetVolume_Quarts", 4, DataType.Numeric, 6, false);
        Add("361d", "NetVolume_Gallonen", 4, DataType.Numeric, 6, false);
        Add("362d", "GrossVolume_Quarts", 4, DataType.Numeric, 6, false);
        Add("363d", "GrossVolume_Gallonen", 4, DataType.Numeric, 6, false);
        Add("364d", "NetVolume_CubicInches", 4, DataType.Numeric, 6, false);
        Add("365d", "NetVolume_CubicFeet", 4, DataType.Numeric, 6, false);
        Add("366d", "NetVolume_CubicYards", 4, DataType.Numeric, 6, false);
        Add("367d", "GrossVolume_CubicInches", 4, DataType.Numeric, 6, false);
        Add("368d", "GrossVolume_CubicFeet", 4, DataType.Numeric, 6, false);
        Add("369d", "GrossVolume_CubicYards", 4, DataType.Numeric, 6, false);
        Add("37", "QuantityInParts", 2, DataType.Numeric, 8, true);
        Add("390d", "AmountDue_DefinedValutaBand", 4, DataType.Numeric, 15, true);
        Add("391d", "AmountDue_WithISOValutaCode", 4, DataType.Numeric, 18, true);
        Add("392d", "BePayingAmount_DefinedValutaBand", 4, DataType.Numeric, 15, true);
        Add("393d", "BePayingAmount_WithISOValutaCode", 4, DataType.Numeric, 18, true);
        Add("400", "JobNumberOfGoodsRecipient", 3, DataType.Alphanumeric, 30, true);
        Add("401", "ShippingNumber", 3, DataType.Alphanumeric, 30, true);
        Add("402", "DeliveryNumber", 3, DataType.Numeric, 17, false);
        Add("403", "RoutingCode", 3, DataType.Alphanumeric, 30, true);
        Add("410", "EAN_UCC_GlobalLocationNumber(GLN)_GoodsRecipient", 3, DataType.Numeric, 13, false);
        Add("411", "EAN_UCC_GlobalLocationNumber(GLN)_InvoiceRecipient", 3, DataType.Numeric, 13, false);
        Add("412", "EAN_UCC_GlobalLocationNumber(GLN)_Distributor", 3, DataType.Numeric, 13, false);
        Add("413", "EAN_UCC_GlobalLocationNumber(GLN)_FinalRecipient", 3, DataType.Numeric, 13, false);
        Add("414", "EAN_UCC_GlobalLocationNumber(GLN)_PhysicalLocation", 3, DataType.Numeric, 13, false);
        Add("415", "EAN_UCC_GlobalLocationNumber(GLN)_ToBilligParticipant", 3, DataType.Numeric, 13, false);
        Add("420", "ZipCodeOfRecipient_withoutCountryCode", 3, DataType.Alphanumeric, 20, true);
        Add("421", "ZipCodeOfRecipient_withCountryCode", 3, DataType.Alphanumeric, 12, true);
        Add("422", "BasisCountryOfTheWares_ISO3166Format", 3, DataType.Numeric, 3, false);
        Add("7001", "Nato Stock Number", 4, DataType.Numeric, 13, false);
        Add("8001", "RolesProducts", 4, DataType.Numeric, 14, false);
        Add("8002", "SerialNumberForMobilePhones", 4, DataType.Alphanumeric, 20, true);
        Add("8003", "GlobalReturnableAssetIdentifier", 4, DataType.Alphanumeric, 34, true);
        Add("8004", "GlobalIndividualAssetIdentifier", 4, DataType.Numeric, 30, true);
        Add("8005", "SalesPricePerUnit", 4, DataType.Numeric, 6, false);
        Add("8006", "IdentifikationOfAProductComponent", 4, DataType.Numeric, 18, false);
        Add("8007", "IBAN", 4, DataType.Alphanumeric, 30, true);
        Add("8008", "DataAndTimeOfManufacturing", 4, DataType.Numeric, 12, true);
        Add("8018", "GlobalServiceRelationNumber", 4, DataType.Numeric, 18, false);
        Add("8020", "NumberBillCoverNumber", 4, DataType.Alphanumeric, 25, false);
        Add("8100", "CouponExtendedCode_NSC_offerCcode", 4, DataType.Numeric, 10, false);
        Add("8101", "CouponExtendedCode_NSC_offerCcode_EndOfOfferCode", 4, DataType.Numeric, 14, false);
        Add("8102", "CouponExtendedCode_NSC", 4, DataType.Numeric, 6, false);
        Add("90", "InformationForBilateralCoordinatedApplications", 2, DataType.Alphanumeric, 30, true);
        //Add("91", "Company specific", 2, DataType.Alphanumeric, 30, true);
        //Add("92", "Company specific", 2, DataType.Alphanumeric, 30, true);
        //Add("93", "Company specific", 2, DataType.Alphanumeric, 30, true);
        //Add("94", "Company specific", 2, DataType.Alphanumeric, 30, true);
        //Add("95", "Company specific", 2, DataType.Alphanumeric, 30, true);
        //Add("96", "Company specific", 2, DataType.Alphanumeric, 30, true);
        //Add("97", "Company specific", 2, DataType.Alphanumeric, 30, true);
        //Add("98", "Company specific", 2, DataType.Alphanumeric, 30, true);
        //Add("99", "Company specific", 2, DataType.Alphanumeric, 30, true);
        aiis = aiiDict.Keys.ToArray();
        minLengthOfAI = aiiDict.Values.Min(el => el.LengthOfAI);
        maxLengthOfAI = aiiDict.Values.Max(el => el.LengthOfAI);

    }
    /// <summary>
    /// Add an Application Identifier (AI)
    /// </summary>
    /// <param name="AI">Number of the AI</param>
    /// <param name="Description"></param>
    /// <param name="LengthOfAI"></param>
    /// <param name="DataDescription">The type of the content</param>
    /// <param name="LengthOfData">The max lenght of the content</param>
    /// <param name="FNC1">Support a group seperator</param>
    public static void Add(string AI, string Description, int LengthOfAI, DataType DataDescription, int LengthOfData, bool FNC1)
    {
        aiiDict[AI] = new AII(AI, Description, LengthOfAI, DataDescription, LengthOfData, FNC1);
    }

    /// <summary>
    /// Parse the ean128 code
    /// </summary>
    /// <param name="data">The raw scanner data</param>
    /// <param name="throwException">If an exception will be thrown if an AI cannot be found</param>
    /// <returns>The different parts of the ean128 code</returns>
    public static Dictionary<AII, string> Parse(string data, bool throwException = false)
    {
        // cut off the EAN128 start code 
        if (data.StartsWith(EAN128StartCode))
            data = data.Substring(EAN128StartCode.Length);
        // cut off the check sum
        if (HasCheckSum)
            data = data.Substring(0, data.Length - 2);

        Dictionary<AII, string> result = new Dictionary<AII, string>();
        int index = 0;
        // walkk through the EAN128 code
        while (index < data.Length)
        {
            // try to get the AI at the current position
            var ai = GetAI(data, ref index);
            if (ai == null)
            {
                if(throwException)
                    throw new InvalidOperationException("AI not found");
                return result;
            }
            // get the data to the current AI
            string code = GetCode(data, ai, ref index);
            result[ai] = code;
        }

        return result;
    }

    /// <summary>
    /// Try to get the AI at the current position
    /// </summary>
    /// <param name="data">The row data from the scanner</param>
    /// <param name="index">The refrence of the current position</param>
    /// <param name="usePlaceHolder">Sets if the last character of the AI should replaced with a placehoder ("d")</param>
    /// <returns>The current AI or null if no match was found</returns>
    private static AII GetAI(string data, ref int index, bool usePlaceHolder = false)
    {
        AII result = null;
        // Step through the different lenghts of the AIs
        for (int i = minLengthOfAI; i <= maxLengthOfAI; i++)
        {
            // get the AI sub string
            string ai = data.Substring(index, i);
            if (usePlaceHolder)
                ai = ai.Remove(ai.Length - 1) + "d";
            // try to get the ai from the dictionary
            if (aiiDict.TryGetValue(ai, out result))
            {
                // Shift the index to the next
                index += i;
                return result;
            }
            // if no AI found, try it with the next lenght
        }
        // if no AI found here, than try it with placeholders. Assumed that is the first sep where usePlaceHolder is false
        if (!usePlaceHolder)
            result = GetAI(data, ref index, true);
        return result;
    }

    /// <summary>
    /// Get the current code to the AI
    /// </summary>
    /// <param name="data">The row data from the scanner</param>
    /// <param name="ai">The current AI</param>
    /// <param name="index">The refrence of the current position</param>
    /// <returns>the data to the current AI</returns>
    private static string GetCode(string data, AII ai, ref int index)
    {
        // get the max lenght to read.
        int lenghtToRead = Math.Min(ai.LengthOfData, data.Length - index);
        // get the data of the current AI
        string result = data.Substring(index, lenghtToRead);
        // check if the AI support a group seperator
        if (ai.FNC1)
        {
            // try to find the index of the group seperator
            int indexOfGroupTermination = result.IndexOf(GroutSeperator);
            if (indexOfGroupTermination >= 0)
                lenghtToRead = indexOfGroupTermination + 1;
            // get the data of the current AI till the gorup seperator
            result = data.Substring(index, lenghtToRead);
        }

        // Shift the index to the next
        index += lenghtToRead;
        return result;
    }
}

答案 1 :(得分:1)

正则表达式不合适或者我不能这样做,但这是我的解决方案。我希望对于遇到同样问题的人有用。

    private void GS1DataConvert(string pBarcode)
    {
        String aiFull = "";
        String aiWCheckSum = "";
        String aiValue = "";
        Int32 aiCheckSum = 0;
        Int32 aiMinLength = 0;
        Int32 aiMaxLength = 0;
        int index = 0;
        if (pBarcode.Contains("01"))
        {
            index = pBarcode.IndexOf("01") + 2;
            AII sai = getAiInfo("01");
            aiMinLength = sai.minLength;
            aiMaxLength = sai.maxLength;

            aiFull = pBarcode.Substring(index - 2, aiMaxLength + 2);
            aiWCheckSum = pBarcode.Substring(index, aiMaxLength);
            aiValue = aiWCheckSum.Remove(aiWCheckSum.Length - 1, 1);
            aiCheckSum = Int32.Parse(aiWCheckSum.Substring(aiWCheckSum.Length - 1, 1));
            if (checkSum(aiValue, aiCheckSum))
            {
                pBarcode = pBarcode.Replace(aiFull, String.Empty);
                textBox2.Text = aiValue;
            }
        }
        if (pBarcode.Contains("17"))
        {
            index = pBarcode.IndexOf("17") + 2;
            AII sai = getAiInfo("17");
            aiFull = pBarcode.Substring(index-2, sai.minLength+2);
            aiValue = pBarcode.Substring(index, sai.minLength);
            if (checkDate(aiValue)>DateTime.MinValue)
            {
                pBarcode = pBarcode.Replace(aiFull, String.Empty);
                textBox3.Text = aiValue;
            }
        }
        if(pBarcode.Contains("10"))
        {
            index = pBarcode.IndexOf("10") + 2;
            AII sai = getAiInfo("10");
            aiMinLength = sai.minLength;
            aiMaxLength = pBarcode.Length<sai.maxLength ? pBarcode.Length-2 : sai.maxLength;
            aiFull = pBarcode.Substring(index - 2, aiMaxLength + 2);
            aiValue = pBarcode.Substring(index, aiMaxLength);
            textBox4.Text = aiValue;
        }


    }


    private Boolean  checkSum (String pgtin,Int32 pchecksum)
    {
        Boolean ret = false;
        Int32 glength = 0;
        Int32 total = 0;
        Int32 cSum = 0;
        Int32[] mutiply = { 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3 };
        glength = 17 - pgtin.Length;
        for (int i = 0; i < pgtin.Length; i++)
        {
            total = total + (Int32.Parse(pgtin[i].ToString()) * mutiply[i + glength]);
        }
        cSum = 10 - (total % 10);
        if (cSum == pchecksum)
        {
            ret = true;
        }
        return ret;

    }

    private DateTime checkDate(string pdate)
    {
        DateTime ret = DateTime.MinValue;
        DateTime convertedDate = DateTime.MinValue;
        String dFormat = "yyMMdd";
        if (DateTime.TryParseExact(pdate, dFormat, CultureInfo.CurrentCulture, DateTimeStyles.None, out convertedDate))
        {
            ret = convertedDate;
        }
        return ret;
    }

    public AII getAiInfo(String pAi)
    {
        AII naii = new AII();
        if (pAi=="01")
        {
            naii.AICode = "01";
            naii.minLength = 8;
            naii.maxLength = 14;
            return naii;
        }
        if (pAi == "17")
        {
            naii.AICode = "17";
            naii.minLength = 6;
            naii.minLength = 6;
            return naii;
        }
        if (pAi == "10")
        {
            naii.AICode = "10";
            naii.minLength = 1;
            naii.maxLength = 20;
        }

        return naii;
    }


    public struct AII
    {
        public String AICode;
        public Int32 minLength;
        public Int32 maxLength;
    }

使用

   private void button1_Click(object sender, EventArgs e)
    {
        string barcode = textBox1.Text;
        GS1DataConvert(barcode);

    }

答案 2 :(得分:1)

我发现RegEx仍然有用。在下面的代码中,我使用了一个锯齿状的字符串数组,其中包含我希望能够处理的AI及其属性:

        string[][] arrKnownAIs = new string[9][] { //AI, description, min length, max length, type, decimal point indicator? 
                                new string[] { "00", "SSCC", "18", "18", "numeric", "false"}, 
                                new string[] { "02", "GTIN", "14", "14", "numeric", "false"},
                                new string[] { "10", "Batch or lot number","1", "20", "alphanumeric", "false"},
                                new string[] { "15", "Best before date", "6", "6", "numeric", "false"},
                                new string[] { "37", "Number of units contained", "1", "8", "numeric", "false"},
                                new string[] { "400", "Customer's purchase order number", "1", "29", "alphanumeric", "false"},
                                new string[] { "8005", "Price per unit of measure", "6", "6", "numeric", "false"},
                                new string[] { "310", "Netto weight in kilograms", "7", "7", "numeric", "true"},
                                new string[] { "315", "Netto volume in liters", "7", "7", "numeric", "true"},
                              };

我使用这个数组来检查函数的以下提取中的AI(循环上面的数组循环)

strAI = arrAI[0];
            intMin = int.Parse(arrAI[2]);
            intMax = int.Parse(arrAI[3]);
            strType = arrAI[4];

strRegExMatch = "";
            if (strType == "alphanumeric")
            {
                strRegExMatch = Regex.Match(tmpBarcode, strAI + @"\w{" + intMin + "," + intMax + "}").ToString();
            }
            else
            {
                strRegExMatch = Regex.Match(tmpBarcode, strAI + @"\d{" + intMin + "," + intMax + "}").ToString();
            }

            if (strRegExMatch.Length > 0)
            {
                tmpBarcode = Regex.Replace(tmpBarcode, strRegExMatch, ""); //remove the AI and its value so that its value can't be confused as another AI
                strRegExMatch = Regex.Replace(strRegExMatch, strAI, ""); //remove the AI from the match
                arrAIs[arrayIndex] = new string[] { strAI, strRegExMatch };
            }
            arrayIndex++;

希望这有用!

答案 3 :(得分:0)

Debock D.解决方案中存在一个错误。

(错误的)结果是

01:08888893102146;

10:W40190; (正确 10:W1040190; 它取代所有“10”,不仅仅是第一个)

17:120315;

这是我的解决方案

using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace Mobile.Util
{
    public class BarcodeUtil
    {
        public static string AI_SSCC = "00";
        public static string AI_GTIN = "01";
        public static string AI_GTIN_B = "02";
        public static string AI_LOT_NUMBER = "10";
        public static string AI_DATE_PRODUCTION = "11";
        public static string AI_DATE_DUE = "12";
        public static string AI_DATE_PACKING = "13";
        public static string AI_DATE_BEST_BEFORE = "15";
        public static string AI_DATE_SELL_BY = "16";
        public static string AI_DATE_EXPIRATION = "17";
        public static string AI_PRODUCT_VARIANT = "20";
        public static string AI_SERIAL_NUMBER = "21";

        public static int AI_TYPE_DATE = 1;
        public static int AI_TYPE_ALPHANUMERIC = 2;
        public static int AI_TYPE_NUMERIC = 3;


        public class AII
        {
            public string AICode { set; get; }
            public string AIDesc { set; get; }
            public int minLength { set; get; }
            public int maxLength { set; get; }
            public int type { set; get; }
            public string AIValue { set; get; }


            public AII(string aicode, string aiDesc, int minLen, int maxLen, int type)
            {
                this.AICode = aicode;
                this.AIDesc = aiDesc;
                this.minLength = minLen;
                this.maxLength = maxLen;
                this.type = type;
                this.AIValue = "";
            }
            public AII(AII ai)
            {
                this.AICode = ai.AICode;
                this.AIDesc = ai.AIDesc;
                this.minLength = ai.minLength;
                this.maxLength = ai.maxLength;
                this.type = ai.type;
                this.AIValue = ai.AIValue;
            }
        }

        public static Dictionary<string, AII> GS1_AI = new Dictionary<string, AII>() { //AI, description, min length, max length, type, decimal point indicator? 
                        {AI_SSCC, new AII(AI_SSCC, "SSCC",18, 18, AI_TYPE_NUMERIC)},
                        {AI_GTIN,new AII(AI_GTIN, "Identification of a Variable Measure Trade Item (GTIN)", 14,14, AI_TYPE_NUMERIC)},
                        {AI_GTIN_B,new AII( AI_GTIN_B, "Identification of Variable Measure Trade Items Contained in a Logistic", 14, 14, AI_TYPE_NUMERIC)},
                        {AI_LOT_NUMBER,new AII( AI_LOT_NUMBER, "Batch or lot number",1, 20, AI_TYPE_ALPHANUMERIC)},
                        {AI_DATE_PRODUCTION,new AII(  AI_DATE_PRODUCTION, "Production Date",6, 6, AI_TYPE_NUMERIC)},//YYMMDD day not mandatory 00
                        {AI_DATE_DUE,new AII( AI_DATE_DUE, "Due Date for Amount on Payment Slip",6, 6, AI_TYPE_NUMERIC)}, //YYMMDD day not mandatory 00
                        {AI_DATE_PACKING,new AII( AI_DATE_PACKING, "Packaging Date",6, 6, AI_TYPE_NUMERIC)},//YYMMDD day not mandatory 00
                        {AI_DATE_BEST_BEFORE,new AII( AI_DATE_BEST_BEFORE, "Best before date", 6, 6, AI_TYPE_NUMERIC)},//YYMMDD day not mandatory 00
                        {AI_DATE_SELL_BY,new AII( AI_DATE_SELL_BY, "Sell By Date", 6, 6, AI_TYPE_NUMERIC)},//YYMMDD day not mandatory 00
                        {AI_DATE_EXPIRATION,new AII( AI_DATE_EXPIRATION, "Expiration Date", 6, 6, AI_TYPE_NUMERIC)},//YYMMDD day not mandatory 00
                        {AI_PRODUCT_VARIANT,new AII( "20", "Product Variant", 2, 2, AI_TYPE_ALPHANUMERIC)},
                        {AI_SERIAL_NUMBER,new AII( AI_SERIAL_NUMBER, "Serial Number",1, 20, AI_TYPE_ALPHANUMERIC)}, 
                                //{AI_,new AII( "240", "Additional Product Identification Assigned by the Manufacturer", 1, 30, AI_TYPE_ALPHANUMERIC}, 
                                //{AI_,new AII( "241", "Customer Part Number",1,30, AI_TYPE_ALPHANUMERIC)}, 

                                //{AI_,new AII( "37", "Number of units contained", 1, 8, AI_TYPE_NUMERIC)},
                                //{AI_,new AII( "400", "Customer's purchase order number", 1, 29, AI_TYPE_ALPHANUMERIC)},
                                //{AI_,new AII( "8005", "Price per unit of measure", 6, 6, AI_TYPE_NUMERIC)},
                                //{AI_,new AII( "310", "Netto weight in kilograms", 7, 7, AI_TYPE_NUMERIC)},
                                //{AI_,new AII( "315", "Netto volume in liters", 7, 7, AI_TYPE_NUMERIC)},
                       };


        public static Dictionary<string, string> decodeBarcodeGS1_128(string barcode)
        {
            Dictionary<string, string> barcode_decoded = new Dictionary<string, string>();
            barcode = barcode.Replace(")", "").Replace("(", "");
            foreach (KeyValuePair<string, AII> entry in GS1_AI)
            {
                string strAI = entry.Value.AICode;
                int intMin = entry.Value.minLength;
                int intMax = entry.Value.maxLength;
                int strType = entry.Value.type;

                string strRegExMatch = "";
                string matchString;
                if (strType == AI_TYPE_ALPHANUMERIC)
                {
                    strRegExMatch = Regex.Match(barcode, strAI + @"\w{" + intMin + "," + intMax + "}").ToString();
                }
                else if (strType == AI_TYPE_NUMERIC)
                {
                    strRegExMatch = Regex.Match(barcode, strAI + @"\d{" + intMin + "," + intMax + "}").ToString();
                }

                if (strRegExMatch.Length > 0)
                {
                    barcode = Regex.Replace(barcode, strRegExMatch, ""); //remove the AI and its value so that its value can't be confused as another AI
                    var regex = new Regex(Regex.Escape(strAI));
                    strRegExMatch = regex.Replace(strRegExMatch, "", 1);
                    barcode_decoded.Add(strAI, strRegExMatch);

                }

            }
            return barcode_decoded;
        }

    }
}