Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Validate a Containernumber string with the DIN EN ISO 6346 Formula

0.00/5 (No votes)
28 Apr 2014 1  
A class that performs a validation of a container number string using the DIN EN ISO 6346 Formula

Introduction

In logistics companies, sometimes you have to check if an ISO Containernumber is valid or not. The validation depends on the last number of the ISO Containernumber. This tip shows how to accomplish this validation.

Background

If anyone is interested in how the validation has to be done step by step, please visit this page.

Using the Code

The main part of the validation class is the ISO Alphabet Dictionary. It contains all chars used in the ISO standard and the int that contains the char. Because the class and all parts of it are static, the getter of the Alphabet dictionary is checked for null. If it is null, it adds all chars to it. Using it like this, the Dictionary won't be created and filled every time this class is called. Not a big improvement for the performance, but every millisecond counts. ;)

As mentioned, the Alphabet dictionary field and properties look like this:

//Alphabed and the parent Number from the DIN EN ISO 6346 Standard
        private static Dictionary<char, int> _Alphabet;

        /// <summary>
        /// ISO Validation Alphabed in a dictionary
        /// </summary>
        private static Dictionary<char, int> Alphabet
        {
            get {
                if (_Alphabet == null)
                {
                    //If _Alphabed is null initialize new dictionary and fill it
                    _Alphabet = new Dictionary<char, int>();

                    //Add Letters
                    _Alphabet.Add('A', 10);
                    _Alphabet.Add('B', 12);
                    _Alphabet.Add('C', 13);
                    _Alphabet.Add('D', 14);
                    _Alphabet.Add('E', 15);
                    _Alphabet.Add('F', 16);
                    _Alphabet.Add('G', 17);
                    _Alphabet.Add('H', 18);
                    _Alphabet.Add('I', 19);
                    _Alphabet.Add('J', 20);
                    _Alphabet.Add('K', 21);
                    _Alphabet.Add('L', 23);
                    _Alphabet.Add('M', 24);
                    _Alphabet.Add('N', 25);
                    _Alphabet.Add('O', 26);
                    _Alphabet.Add('P', 27);
                    _Alphabet.Add('Q', 28);
                    _Alphabet.Add('R', 29);
                    _Alphabet.Add('S', 30);
                    _Alphabet.Add('T', 31);
                    _Alphabet.Add('U', 32);
                    _Alphabet.Add('V', 34);
                    _Alphabet.Add('W', 35);
                    _Alphabet.Add('X', 36);
                    _Alphabet.Add('Y', 37);
                    _Alphabet.Add('Z', 38);

                    //Add Numbers
                    _Alphabet.Add('0', 0);
                    _Alphabet.Add('1', 1);
                    _Alphabet.Add('2', 2);
                    _Alphabet.Add('3', 3);
                    _Alphabet.Add('4', 4);
                    _Alphabet.Add('5', 5);
                    _Alphabet.Add('6', 6);
                    _Alphabet.Add('7', 7);
                    _Alphabet.Add('8', 8);
                    _Alphabet.Add('9', 9);
                }

                return _Alphabet;
            }
        }  

The bool that determines if the ISO Containernumber is valid or not retrieves a string value that represents the ISO Containernumber to check. In this code snippet, there are other methods that we will look at one by one.

/// <summary>
/// Check if a Container number string is valid or not
/// </summary>
/// <param name="containerNumberToCheck">Container number string that has to be checked for validation</param>
/// <returns>Boolean that shows if the Container number string is valid or not</returns>
public static bool Check(string containerNumberToCheck)
{
    //Clean the input string from Chars that are not in the Alphabed
    string containerNumber = CleanConNumberString(containerNumberToCheck);
    
    //Return true if the input string is empty
    //Used mostly for DataGridView to set the False validation only on false Container Numbers
    //and not empty ones
    if (containerNumber == string.Empty) return true;
    
    //Return False if the input string has not enough Characters
    if (containerNumber.Length != 11) return false;
    
    //Get the Sum of the ISO Formula
    double summ = GetSumm(containerNumber);
    
    //Calculate the Check number with the ISO Formula
    double tempCheckNumber = summ - (Math.Floor(summ / 11) * 11);
    
    //Set temCheckNumber 0 if it is 10 - In some cases this is needed
    if (tempCheckNumber == 10) tempCheckNumber = 0;
    
    //Return true if the calculated check number matches with the input check number
    if (tempCheckNumber == GetCheckNumber(containerNumber))
        return true;
    
    //If no match return false
    return false;
} 

The first is CleanConNumberString. It is used to remove all Chars in the Input string representing the ISO Containernumber. It loops through all chars in the Inputstring and checks if that char exists in the Alphabet dictionary. If it doesn't exist, it replaces that char with an empty string (short way to remove a char from a string ;) ).

/// <summary>
/// Clean a Container number string from Chars that are not in the ISO Alphabed dictionary
/// </summary>
/// <param name="inputString">String that has to be cleaned</param>
/// <returns>String that is cleaned from incorrect Chars</returns>
private static string CleanConNumberString(string inputString)
{
    //Set all Chars to Upper
    string resultString = inputString.ToUpper();
    
    //Loop Trough all chars
    foreach (char c in inputString)
    {
        //Remove Char if its not in the ISO Alphabet
        if (!Alphabet.Keys.Contains(c)) 
            resultString=resultString.Replace(c.ToString(), string.Empty); //Remove chars with the String.Replace Method
    }
    
    //Return the cleaned String
    return resultString;
} 

The next is the GetSumm double. In it, we get the specified Summ defined with the ISO standard. As mentioned, you can get more information about that at this page. The summ is an addition of the Char number from the Alphabet dictionary multiplied with 2 that is "powed" with the Char index in the Inputstring.

/// <summary>
/// Calculate the sum by the ISO Formula
/// </summary>
/// <param name="inputString">String of the Container number</param>
/// <returns></returns>
private static double GetSumm(string inputString)
{
    //Set summ to 0
    double summ = 0;
    
    //Calculate only if the container string is not empty
    if (inputString.Length > 1)
    {
        //Loop through all chars in the container string
        //EXCEPT the last char!!!
        for (int i = 0; i < inputString.Length - 1; i++)
        {
            //Get the current char
            char temChar = inputString[i];
            
            //Initialise a integer to represent the char number in the ISO Alphabet
            //Set it to 0
            int charNumber=0;
            
            //If Char exists in the Table get it´s number
            if(Alphabet.Keys.Contains(temChar))
                charNumber = Alphabet[temChar];
                
            //Add the char number to the sum using the ISO Formula
            summ += charNumber * (Math.Pow(2, i));
        }
    }
    
    //Return the calculated summ
    return summ;
} 

Also, an important int that we need is the "Check digit". It's just the last Char of the Inputstring converted to an int. It is important that we return 11 if we can't convert the char to an int. In that case, we will surely get false for the ISO Containernumber validation because the Check digit can't be 11 ;).

/// <summary>
/// Provides the Check number from a Container number string
/// </summary>
/// <param name="inputString">String of the Container number</param>
/// <returns>Integer of the Check number</returns>
private static int GetCheckNumber(string inputString)
{
    //Loop if string is longer than 1
    if (inputString.Length > 1)
    {
        //Get the last char of the string
        char checkChar = inputString[inputString.Length - 1];
        
        //Initialise a integer
        int CheckNumber = 0;
        
        //Parse the last char to a integer
        if (Int32.TryParse(checkChar.ToString(), out CheckNumber))
            return CheckNumber; //Return the integer if the parsing can be done
        
    }
    
    //If parsing can´t be done and the string has just 1 char or is empty
    //Return 11 (A number that can´t be a check number!!!)
    return 11;
} 

Let´s take a look again at the method that returns the important bool value going through it step by step.

  1. We clean the inputstring
  2. Return false if the string doesn't have enough chars or is empty (good if this code is used in DataGridView)
  3. We get the ISO Summ
  4. We calculate the tempCheckNumber or the temCheckdigit
  5. VERY IMPORTANT - if the temCheck digit is 10, we set its value to 0
  6. FINALLY, if the tempCheckNumber is equal to the real CheckNumber, the Containernumber string is valid :)
/// <summary>
/// Check if a Container number string is valid or not
/// </summary>
/// <param name="containerNumberToCheck">Container number string that has to be checked for validation</param>
/// <returns>Boolean that shows if the Container number string is valid or not</returns>
public static bool Check(string containerNumberToCheck)
{
    //Clean the input string from Chars that are not in the Alphabed
    string containerNumber = CleanConNumberString(containerNumberToCheck);
    
    //Return true if the input string is empty
    //Used mostly for DataGridView to set the False validation only on false Container Numbers
    //and not empty ones
    if (containerNumber == string.Empty) return true;
    
    //Return False if the input string has not enough Characters
    if (containerNumber.Length != 11) return false;
    
    //Get the Sum of the ISO Formula
    double summ = GetSumm(containerNumber);
    
    //Calculate the Check number with the ISO Formula
    double tempCheckNumber = summ - (Math.Floor(summ / 11) * 11);
    
    //Set temCheckNumber 0 if it is 10 - In somme cases this is needed
    if (tempCheckNumber == 10) tempCheckNumber = 0;
    
    //Return true if the calculated check number matches with the input check number
    if (tempCheckNumber == GetCheckNumber(containerNumber))
        return true;
    
    //If no match return false
    return false;
} 

Code of the Class

  /// <summary>
    /// Validate if Container number passes the DIN EN ISO 6346 validation Formula
    /// </summary>
    /// <example>
    /// <code>if(ContainerNumberValidation(Check("Containernumber")) Console.WriteLine("Number is OK");</code></example>
    public static class ContainerNumber
    {
        //Alphabed and the parent Number from the DIN EN ISO 6346 Standard
        private static Dictionary<char, int> _Alphabet;

        /// <summary>
        /// ISO Validation Alphabed in a dictionary
        /// </summary>
        private static Dictionary<char, int> Alphabet
        {
            get {
                if (_Alphabet == null)
                {
                    //If _Alphabed is null Initialise new dictionary and fill it
                    _Alphabet = new Dictionary<char, int>();

                    //Add Letters
                    _Alphabet.Add('A', 10);
                    _Alphabet.Add('B', 12);
                    _Alphabet.Add('C', 13);
                    _Alphabet.Add('D', 14);
                    _Alphabet.Add('E', 15);
                    _Alphabet.Add('F', 16);
                    _Alphabet.Add('G', 17);
                    _Alphabet.Add('H', 18);
                    _Alphabet.Add('I', 19);
                    _Alphabet.Add('J', 20);
                    _Alphabet.Add('K', 21);
                    _Alphabet.Add('L', 23);
                    _Alphabet.Add('M', 24);
                    _Alphabet.Add('N', 25);
                    _Alphabet.Add('O', 26);
                    _Alphabet.Add('P', 27);
                    _Alphabet.Add('Q', 28);
                    _Alphabet.Add('R', 29);
                    _Alphabet.Add('S', 30);
                    _Alphabet.Add('T', 31);
                    _Alphabet.Add('U', 32);
                    _Alphabet.Add('V', 34);
                    _Alphabet.Add('W', 35);
                    _Alphabet.Add('X', 36);
                    _Alphabet.Add('Y', 37);
                    _Alphabet.Add('Z', 38);

                    //Add Numbers
                    _Alphabet.Add('0', 0);
                    _Alphabet.Add('1', 1);
                    _Alphabet.Add('2', 2);
                    _Alphabet.Add('3', 3);
                    _Alphabet.Add('4', 4);
                    _Alphabet.Add('5', 5);
                    _Alphabet.Add('6', 6);
                    _Alphabet.Add('7', 7);
                    _Alphabet.Add('8', 8);
                    _Alphabet.Add('9', 9);
                }

                return _Alphabet;
            }
        }

        /// <summary>
        /// Check if a Container number string is valid or not
        /// </summary>
        /// <param name="containerNumberToCheck">Container number string that has to be checked for validation</param>
        /// <returns>Boolean that shows if the Container number string is valid or not</returns>
        public static bool Check(string containerNumberToCheck)
        {
            //Clean the input string from Chars that are not in the Alphabed
            string containerNumber = CleanConNumberString(containerNumberToCheck);

            //Return true if the input string is empty
            //Used mostly for DataGridView to set the False validation only on false Container Numbers
            //and not empty ones
            if (containerNumber == string.Empty) return true;

            //Return False if the input string has not enough Characters
            if (containerNumber.Length != 11) return false;
            
            //Get the Sum of the ISO Formula
            double summ = GetSumm(containerNumber);

            //Calculate the Check number with the ISO Formula
            double tempCheckNumber = summ - (Math.Floor(summ / 11) * 11);

            //Set temCheckNumber 0 if it is 10 - In somme cases this is needed
            if (tempCheckNumber == 10) tempCheckNumber = 0;

            //Return true if the calculated check number matches with the input check number
            if (tempCheckNumber == GetCheckNumber(containerNumber))
                return true;
            
            //If no match return false
            return false;
        }

        /// <summary>
        /// Clean a Container number string from Chars that are not in the ISO Alphabed dictionary
        /// </summary>
        /// <param name="inputString">String that has to be cleaned</param>
        /// <returns>String that is cleaned from incorrect Chars</returns>
        private static string CleanConNumberString(string inputString)
        {
            //Set all Chars to Upper
            string resultString = inputString.ToUpper();

            //Loop Trough all chars
            foreach (char c in inputString)
            {
                //Remove Char if its not in the ISO Alphabet
                if (!Alphabet.Keys.Contains(c)) 
                    resultString=resultString.Replace(c.ToString(), string.Empty); //Remove chars with the String.Replace Method
            }

            //Return the cleaned String
            return resultString;
        }

        /// <summary>
        /// Provides the Check number from a Container number string
        /// </summary>
        /// <param name="inputString">String of the Container number</param>
        /// <returns>Integer of the Check number</returns>
        private static int GetCheckNumber(string inputString)
        {
            //Loop if string is longer than 1
            if (inputString.Length > 1)
            {
                //Get the last char of the string
                char checkChar = inputString[inputString.Length - 1];

                //Initialise a integer
                int CheckNumber = 0;

                //Parse the last char to a integer
                if (Int32.TryParse(checkChar.ToString(), out CheckNumber))
                    return CheckNumber; //Return the integer if the parsing can be done
                
            }

            //If parsing can´t be done and the string has just 1 char or is empty
            //Return 11 (A number that can´t be a check number!!!)
            return 11;
        }

        /// <summary>
        /// Calculate the sum by the ISO Formula
        /// </summary>
        /// <param name="inputString">String of the Container number</param>
        /// <returns></returns>
        private static double GetSumm(string inputString)
        {
            //Set summ to 0
            double summ = 0;

            //Calculate only if the container string is not empty
            if (inputString.Length > 1)
            {
                //Loop through all chars in the container string
                //EXCEPT the last char!!!
                for (int i = 0; i < inputString.Length - 1; i++)
                {
                    //Get the current char
                    char temChar = inputString[i];

                    //Initialise a integer to represent the char number in the ISO Alphabet
                    //Set it to 0
                    int charNumber=0;

                    //If Char exists in the Table get it´s number
                    if(Alphabet.Keys.Contains(temChar))
                        charNumber = Alphabet[temChar];

                    //Add the char number to the sum using the ISO Formula
                    summ += charNumber * (Math.Pow(2, i));
                }
            }

            //Return the calculated summ
            return summ;
        }
    } 

How to Use the Class

Usage in a WinForm Control

Now we will show how to use this Class in a WinForm. Because it is a static class, it does not need to be initialized. This makes the code snippet of the usage much smaller. In this case, the used control turns Green if the Containernumber is alright and Red if not.

private void btnCheckContainerNumber_Click(object sender, EventArgs e)
{
    string containerNumberToCheck = txtContainerNumber.Text;
    bool validated= ContainerNumber.Check(containerNumberToCheck);
    
    if (validated)
    {
        txtContainerNumber.BackColor = Color.Green;
    }
    else
    {
        txtContainerNumber.BackColor = Color.Red;
    }    
} 

Usage in a WinForm DataGridView

The class can be used in a DataGridView with no loss of performance. If we set the usage in a Cell_Formatting event, the code will be called only if the cell is Shown/Formatting. In that case, the DataGridView can have thousands of rows and the performance will be the same. Actually, this is how I use the code in my project. It is in an override void because my DataGridViews are made by a DataGridView class but the usage is the same in a normal CellFormatting event.

Because my DataGridView is made by a class (and I can't be sure if the class has accomplished its code), I have to check if the DataGridView contains the Column in which the Containernumber is stored.

After that, we just call our class and use the bool value to paint the cell in Red if the Containernumber is not valid and leave it as if the Containernumber is Valid.

public override void CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
    DataGridView dgv = sender as DataGridView;
    DataGridViewRow row = dgv.Rows[e.RowIndex];
    
    string conNr = string.Empty;
    if (dgv.Columns.Contains("ConNr"))
    {
        conNr = row.Cells["ConNr"].Value.ToString();
        if (!ContainerNumber.Check(conNr))
            row.Cells["ConNr"].Style.BackColor = Color.Red;
    }            
} 

Beside that, if we use the code in a DataGridVew, we would not like to show empty cells as False/Red. It would just make too many Red cells. The users could get adjusted to it and just not notice "real" invalid Containernumbers. Because of that, I made a small change in the bool method in our class:

//Return True if the input string is Empty
if (containerNumber == string.Empty) return true;
//Return False if the input string has not enough Characters
if (containerNumber.Length != 11) return false; 

This way, ONLY the invalid Containernumbers will be Red and all other cells are empty or contain a valid Containernumber. :)

Points of Interest

This code is the first one I ever used the Math class with Pow, Floor, etc. :D

History

  • Second version of the demo
  • 07.05.2014 - Third version (XML documentation added)

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here