Click here to Skip to main content
15,860,972 members
Articles / Programming Languages / C#
Tip/Trick

Validate a Containernumber string with the DIN EN ISO 6346 Formula

Rate me:
Please Sign up or sign in to vote.
4.86/5 (3 votes)
28 Apr 2014CPOL4 min read 20.4K   5   2
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:

C#
//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.

C#
/// <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 ;) ).

C#
/// <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.

C#
/// <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 ;).

C#
/// <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 :)
C#
/// <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

C#
/// <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.

C#
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.

C#
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:

C#
//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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Engineer ICS Logistik & Transport GmbH
Germany Germany
Born in Bosnia and Herzegowina where I studied Traffic and Communication in the University of Sarajevo. After the Bachelor, found a Job in a Logistic Company in Germany where I live and work now as an Software developer for our Company needs.

With programming I started as an hoby at work. For now I have almost 2 years programing experience. First with excel then VBA in Excel. That growed up to VBA with Access and a first Access DB. Then an SQL Server camed in and VBA with Access could not handle it. The next move was of cource VB.Net but with Visual Studio I came in contact with C#.

Comments and Discussions

 
QuestionThank you Pin
iceman50872-Jan-16 4:27
iceman50872-Jan-16 4:27 
GeneralMy vote of 5 Pin
Volynsky Alex29-Apr-14 23:02
professionalVolynsky Alex29-Apr-14 23:02 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.