VB.Net/C# code to calculate a MOD10 check digit

Posted: 11/17/2014

Here is some code that I put together a while back to calculate a MOD10 check digit for a specified value.  These can be handy in structuring account numbers.  By putting a check digit as the last digit you can then validate it when a data entry operator re-enters it helping to ensure that the correct account number was entered and didn't have a typo in it.

The only hiccup is that I'm using some extension methods to identify even/odd values and then also for Left and Right functions.  I will include those extension methods also.  You can also just turn them into functions and include them in the class / call them like functions.

VB.Net Mod10CheckDigit Class

Imports Argus.Extensions

Namespace Argus.Data


    ''' <summary>
    ''' Shared methods for calculating and verifying MOD10 check digits.
    ''' </summary>
    ''' <remarks></remarks>
    Public Class Mod10CheckDigit

        '*********************************************************************************************************************
        '
        '             Class:  Mod10CheckDigit
        '      Organization:  http://www.blakepell.com   
        '      Initial Date:  05/20/2013
        '      Last Updated:  11/17/2014
        '     Programmer(s):  Blake Pell, blakepell@hotmail.com
        '
        '*********************************************************************************************************************

        ''' <summary>
        ''' Returns a check digit for a specified string.
        ''' </summary>
        ''' <param name="txt">The string value to create a check digit for</param>
        ''' <returns>An integer check digit</returns>
        Public Shared Function Calculate(txt As String) As Integer
            Dim baseList As New List(Of String)

            txt = txt.ToUpper

            For x As Integer = 0 To txt.Count - 1
                baseList.Add(GetValue(txt.Substring(x, 1)))
            Next

            Dim calcList As New List(Of String)

            ' Get the new values
            For x As Integer = 0 To baseList.Count - 1
                If x.IsEven = True Then
                    calcList.Add(CInt(baseList(x)) * 1)
                Else
                    calcList.Add(CInt(baseList(x)) * 2)
                End If
            Next

            ' Pad any single digits
            For x As Integer = 0 To calcList.Count - 1
                If calcList(x).Length = 1 Then
                    calcList(x) = "0" & calcList(x)
                End If
            Next

            ' Bust these all up into single digits
            Dim digitList As New List(Of Integer)

            For x As Integer = 0 To calcList.Count - 1
                digitList.Add(CInt(calcList(x).Left(1)))
                digitList.Add(CInt(calcList(x).Right(1)))
            Next

            Dim sumOfDigits As Integer = digitList.Sum
            Dim lastDigit As Integer = CInt(sumOfDigits.ToString.Right(1))

            If lastDigit = 0 Then
                Return 0
            Else
                Return 10 - lastDigit
            End If

        End Function

        ''' <summary>
        ''' Whether or not the specified value is correct (e.g. the check digit matches the rest of the provided value).  The inputted value would
        ''' be the string with the check digit (e.g., a full account number).
        ''' </summary>
        ''' <param name="val">The value with the check digit to validate.</param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Shared Function IsValid(val As String) As Boolean
            If String.IsNullOrWhiteSpace(val) = True Then
                Return False
            ElseIf val.Length = 1 Then
                Return False
            End If

            Dim originalCheckDigit As String = val.SafeRight(1)
            Dim originalWithoutCheckDigit As String = val.SafeLeft(val.Length - 1)

            Dim calculatedCheckDigit As String = Calculate(originalWithoutCheckDigit)

            If calculatedCheckDigit = originalCheckDigit Then
                Return True
            Else
                Return False
            End If
        End Function


        ''' <summary>
        ''' Returns the lookup value as specified in the MOD-10 documentation.
        ''' </summary>
        Public Shared Function GetValue(val As String) As String
            If val.Length > 1 Then
                Throw New Exception("Value has a length of greater than 1")
            End If

            Select Case val
                Case "0"
                    Return "00"
                Case "1"
                    Return "01"
                Case "2"
                    Return "02"
                Case "3"
                    Return "03"
                Case "4"
                    Return "04"
                Case "5"
                    Return "05"
                Case "6"
                    Return "06"
                Case "7"
                    Return "07"
                Case "8"
                    Return "08"
                Case "9"
                    Return "09"
                Case "A"
                    Return "10"
                Case "B"
                    Return "11"
                Case "C"
                    Return "12"
                Case "D"
                    Return "13"
                Case "E"
                    Return "14"
                Case "F"
                    Return "15"
                Case "G"
                    Return "16"
                Case "H"
                    Return "17"
                Case "I"
                    Return "18"
                Case "J"
                    Return "19"
                Case "K"
                    Return "20"
                Case "L"
                    Return "21"
                Case "M"
                    Return "22"
                Case "N"
                    Return "23"
                Case "O"
                    Return "24"
                Case "P"
                    Return "25"
                Case "Q"
                    Return "26"
                Case "R"
                    Return "27"
                Case "S"
                    Return "28"
                Case "T"
                    Return "29"
                Case "U"
                    Return "30"
                Case "V"
                    Return "31"
                Case "W"
                    Return "32"
                Case "X"
                    Return "33"
                Case "Y"
                    Return "34"
                Case "Z"
                    Return "35"
                Case "*"
                    Return "36"
                Case "@"
                    Return "37"
                Case "#"
                    Return "38"
                Case Else
                    Throw New Exception(String.Format("Invalid input. '{0}' is an unsupported character.", val))
            End Select

        End Function

    End Class

End Namespace

VB.Net - Extension Methods

        ''' <summary>
        ''' This function will return the specified amount of characters from the left hand side of the string.  This is the equivalent of the Visual Basic Left function.
        ''' </summary>
        ''' <param name="str"></param>
        ''' <param name="length"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        <Extension()> _
        Public Function [Left](ByVal str As String, ByVal length As Integer) As String            
            Return str.Substring(0, length)            
        End Function

        ''' <summary>
        ''' This function will return the specified amount of characters from the right hand side of the string.  This is the equivalent of the Visual Basic Right function.
        ''' </summary>
        ''' <param name="str"></param>
        ''' <param name="length"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        <Extension()> _
        Public Function [Right](ByVal str As String, ByVal length As Integer) As String
            Return str.Substring(str.Length - length, length)
        End Function

        ''' <summary>
        ''' Returns the specified number of characters from the left hand side of the string.  If the number asked for is longer the
        ''' string then the entire string is returned without an exception.
        ''' </summary>
        ''' <param name="str"></param>
        ''' <param name="length"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        <Extension()> _
        Public Function SafeLeft(ByVal str As String, ByVal length As Integer) As String
            If length >= str.Length Then
                Return str
            ElseIf length < 0 Then
                Return ""
            End If

            Return Left(str, length)
        End Function

        ''' <summary>
        ''' Returns the specified number of characters from the right hand side of the string.  If the number asked for is longer the
        ''' string then the entire string is returned without an exception.
        ''' </summary>
        ''' <param name="str"></param>
        ''' <param name="length"></param>
        ''' <returns></returns>
        ''' <remarks></remarks>
        <Extension()> _
        Public Function SafeRight(ByVal str As String, ByVal length As Integer) As String
            If length >= str.Length Then
                Return str
            ElseIf length < 0 Then
                Return ""
            End If

            Return Right(str, length)
        End Function

C# - Mod10CheckDigit Class

using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using Argus.Extensions;

namespace Argus.Data
{

	/// <summary>
	/// Shared methods for calculating and verifying MOD10 check digits.
	/// </summary>
	/// <remarks></remarks>
	public class Mod10CheckDigit
	{

		//*********************************************************************************************************************
		//
		//             Class:  Mod10CheckDigit
		//      Organization:  http://www.blakepell.com        
		//      Initial Date:  05/20/2013
		//      Last Updated:  11/17/2014
		//     Programmer(s):  Blake Pell, blakepell@hotmail.com
		//
		//*********************************************************************************************************************

		/// <summary>
		/// Returns a check digit for a specified string.
		/// </summary>
		/// <param name="txt">The string value to create a check digit for</param>
		/// <returns>An integer check digit</returns>
		public static int Calculate(string txt)
		{
			List<string> baseList = new List<string>();

			txt = txt.ToUpper;

			for (int x = 0; x <= txt.Count - 1; x++) {
				baseList.Add(GetValue(txt.Substring(x, 1)));
			}

			List<string> calcList = new List<string>();

			// Get the new values
			for (int x = 0; x <= baseList.Count - 1; x++) {
				if (x.IsEven == true) {
					calcList.Add(Convert.ToInt32(baseList(x)) * 1);
				} else {
					calcList.Add(Convert.ToInt32(baseList(x)) * 2);
				}
			}

			// Pad any single digits
			for (int x = 0; x <= calcList.Count - 1; x++) {
				if (calcList(x).Length == 1) {
					calcList(x) = "0" + calcList(x);
				}
			}

			// Bust these all up into single digits
			List<int> digitList = new List<int>();

			for (int x = 0; x <= calcList.Count - 1; x++) {
				digitList.Add(Convert.ToInt32(calcList(x).Left(1)));
				digitList.Add(Convert.ToInt32(calcList(x).Right(1)));
			}

			int sumOfDigits = digitList.Sum;
			int lastDigit = Convert.ToInt32(sumOfDigits.ToString.Right(1));

			if (lastDigit == 0) {
				return 0;
			} else {
				return 10 - lastDigit;
			}

		}

		/// <summary>
		/// Whether or not the specified value is correct (e.g. the check digit matches the rest of the provided value).  The inputted value would
		/// be the string with the check digit (e.g., a full account number).
		/// </summary>
		/// <param name="val">The value with the check digit to validate.</param>
		/// <returns></returns>
		/// <remarks></remarks>
		public static bool IsValid(string val)
		{
			if (string.IsNullOrWhiteSpace(val) == true) {
				return false;
			} else if (val.Length == 1) {
				return false;
			}

			string originalCheckDigit = val.SafeRight(1);
			string originalWithoutCheckDigit = val.SafeLeft(val.Length - 1);

			string calculatedCheckDigit = Calculate(originalWithoutCheckDigit);

			if (calculatedCheckDigit == originalCheckDigit) {
				return true;
			} else {
				return false;
			}
		}


		/// <summary>
		/// Returns the lookup value as specified in the MOD-10 documentation.
		/// </summary>
		public static string GetValue(string val)
		{
			if (val.Length > 1) {
				throw new Exception("Value has a length of greater than 1");
			}

			switch (val) {
				case "0":
					return "00";
				case "1":
					return "01";
				case "2":
					return "02";
				case "3":
					return "03";
				case "4":
					return "04";
				case "5":
					return "05";
				case "6":
					return "06";
				case "7":
					return "07";
				case "8":
					return "08";
				case "9":
					return "09";
				case "A":
					return "10";
				case "B":
					return "11";
				case "C":
					return "12";
				case "D":
					return "13";
				case "E":
					return "14";
				case "F":
					return "15";
				case "G":
					return "16";
				case "H":
					return "17";
				case "I":
					return "18";
				case "J":
					return "19";
				case "K":
					return "20";
				case "L":
					return "21";
				case "M":
					return "22";
				case "N":
					return "23";
				case "O":
					return "24";
				case "P":
					return "25";
				case "Q":
					return "26";
				case "R":
					return "27";
				case "S":
					return "28";
				case "T":
					return "29";
				case "U":
					return "30";
				case "V":
					return "31";
				case "W":
					return "32";
				case "X":
					return "33";
				case "Y":
					return "34";
				case "Z":
					return "35";
				case "*":
					return "36";
				case "@":
					return "37";
				case "#":
					return "38";
				default:
					throw new Exception(string.Format("Invalid input. '{0}' is an unsupported character.", val));
			}

		}

	}

}

C# - Extension Methods

/// <summary>
/// This function will return the specified amount of characters from the left hand side of the string.  This is the equivalent of the Visual Basic Left function.
/// </summary>
/// <param name="str"></param>
/// <param name="length"></param>
/// <returns></returns>
/// <remarks></remarks>
[Extension()]
public string Left(string str, int length)
{
	return str.Substring(0, length);
}

/// <summary>
/// This function will return the specified amount of characters from the right hand side of the string.  This is the equivalent of the Visual Basic Right function.
/// </summary>
/// <param name="str"></param>
/// <param name="length"></param>
/// <returns></returns>
/// <remarks></remarks>
[Extension()]
public string Right(string str, int length)
{
	return str.Substring(str.Length - length, length);
}

/// <summary>
/// Returns the specified number of characters from the left hand side of the string.  If the number asked for is longer the
/// string then the entire string is returned without an exception.
/// </summary>
/// <param name="str"></param>
/// <param name="length"></param>
/// <returns></returns>
/// <remarks></remarks>
[Extension()]
public string SafeLeft(string str, int length)
{
	if (length >= str.Length) {
		return str;
	} else if (length < 0) {
		return "";
	}

	return Strings.Left(str, length);
}

/// <summary>
/// Returns the specified number of characters from the right hand side of the string.  If the number asked for is longer the
/// string then the entire string is returned without an exception.
/// </summary>
/// <param name="str"></param>
/// <param name="length"></param>
/// <returns></returns>
/// <remarks></remarks>
[Extension()]
public string SafeRight(string str, int length)
{
	if (length >= str.Length) {
		return str;
	} else if (length < 0) {
		return "";
	}

	return Strings.Right(str, length);
}