NullifyNetwork

The blog and home page of Simon Soanes
Skip to content
[ Log On ]

Here's one from my distant past but which may be useful to me at some point today. I can actually see plenty of quicker ways to achieve this but it's also well tested for generating/checking credit card check digits:-

/// <summary>
    /// Creates/appends Luhn/Mod10 check digits to a specified numeric string
    /// Goes belly up with a text string.
    /// </summary>
    public class LuhnCheck
    {
        /// <summary>
        /// Initialise the LuhnCheck class with a number
        /// </summary>
        /// <param name="numberToAddDigitTo">The number to do work on</param>
        public LuhnCheck(string numberToAddDigitTo)
        {
            _numberToAddDigitTo = numberToAddDigitTo;
            setupok = true;
        }
        /// <summary>
        /// Initialise the LuhnCheck class without a number to start with
        /// </summary>
        public LuhnCheck()
        {
            _numberToAddDigitTo = "";
        }

        private string _numberToAddDigitTo;
        /// <summary>
        /// The number to work on
        /// </summary>
        public string NumberToAddDigitTo
        {
            get
            {
                return _numberToAddDigitTo;
            }
            set
            {
                _numberToAddDigitTo = value;
                setupok = true;
            }
        }
        private bool setupok = false;

        /// <summary>
        /// Add the check digit to the string and return the whole string
        /// </summary>
        /// <returns>The whole string with added check digit</returns>
        public string AddCheckDigit()
        {
            if (setupok)
            {
                NumberToAddDigitTo += Convert.ToString(CreateCheckDigit());
                return NumberToAddDigitTo;
            }
            else
            {
                throw new ArgumentException("Please specify the number to add the digit to.");
            }
        }
        /// <summary>
        /// Creates a check digit without using it
        /// </summary>
        /// <returns>The check digit</returns>
        public int CreateCheckDigit()
        {
            if (setupok)
            {
                return CreateCheckDigit(NumberToAddDigitTo);
            }
            else
            {
                throw new ArgumentException("Please specify the number to calculate the digit for.");
            }
        }
        /// <summary>
        /// Creates the check digit for a specified numeric string - it does not add it, only calculates it
        /// </summary>
        /// <param name="numberToAddDigitTo">The number to work the check digit out for</param>
        /// <returns>The check digit</returns>
        public int CreateCheckDigit(string numberToAddDigitTo)
        {
            string validChars = "0123456789";
            foreach (char c in numberToAddDigitTo)
            {
                if (!(validChars.IndexOf(c) >= 0))
                    throw new FormatException("The value passed in was not a valid number");
            }

            string tocheckdigit = numberToAddDigitTo + "0"; //We add zero to use it to calculate
            //the number from the correct point - since we'll be alternating between multiplying it by one or two
            int strlen = tocheckdigit.Length;
            int ncheck = 0;
            int nweight = 1; //this will alternate between one and two
            int intermediary = 0;
            string tosplit = "";

            for (int i = 1; i <= strlen; i++) //loop through the card number string
            {
                intermediary = nweight * Convert.ToInt32(Convert.ToString(tocheckdigit[strlen - i])); //make intermediary
//be the multiple of the variance and the card number
                if (intermediary > 9) //if it's bigger than ten...
                {
                    tosplit = Convert.ToString(intermediary);
                    //Split the two digits
                    int firstdigit = Convert.ToInt32(Convert.ToString(tosplit[0]));
                    int seconddigit = Convert.ToInt32(Convert.ToString(tosplit[1]));
                    //Then add them together
                    intermediary = firstdigit + seconddigit;
                }
                //Add the intermediary result to the rolling total
                ncheck += intermediary;
                //Change the variance as per the Luhn formula
                if (nweight == 2)
                {
                    nweight = 1;
                }
                else
                {
                    nweight = 2;
                }
            }
            //ncheck now has the total
            int remainder = 0;
            //Work out the remainder
            Math.DivRem(ncheck, 10, out remainder);
            //return ten minus the remainder (if it's zero then it divides perfectly by ten so is valid,
            //but since we're CREATING a check digit we want to know how far off the result is and how much we
	    //need to correct it using the check digit)
            if (10 - remainder == 10)
            {
                return 0;
            }
            else
            {
                return 10 - remainder;
            }

        }
        /// <summary>
        /// Whether the number stored in the object is a valid MOD 10/Luhn check digited number
        /// </summary>
        public bool IsValid
        {
            get
            {
                if (CreateCheckDigit() == 0)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }
    }
Permalink