Validate a Containernumber string with the DIN EN ISO 6346 Formula






4.86/5 (3 votes)
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 char
s 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 char
s 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 Char
s in the Input string
representing the ISO Containernumber
. It loops through all char
s 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.
- We clean the
inputstring
- Return
false
if thestring
doesn't have enoughchar
s or is empty (good if this code is used inDataGridView
) - We get the ISO
Summ
- We calculate the
tempCheckNumber
or thetemCheckdigit
- VERY IMPORTANT - if the
temCheck
digit is10
, we set its value to0
- FINALLY, if the
tempCheckNumber
is equal to the realCheckNumber
, theContainernumber 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 row
s 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 DataGridView
s 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 Containernumber
s. 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 Containernumber
s 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)