2 thoughts on “Credit card numbers explained”

  1. Did this ages ago.

    Interface…

    package org.r3dux.general;
     
    public interface CheckDigit {
    	public String getCheckDigit(String source);
    	public boolean isCheckDigitValid(String source);
    }

    Implementation…

    package org.r3dux.general.impl;
     
    import org.r3dux.general.CheckDigit;
     
    public class LuhnCheckDigitImpl implements CheckDigit {
    	/**
    	 * Checks if the passed parameter contains only numeric digits.
    	 * 
    	 * @param source A source string
    	 * @since 1.0
    	 * @return true - source contains only numeric characters.  false - source is null or source contains non-numeric characters (including space)
    	 */
    	public static boolean isNumeric(String source) {
    		if (source == null) {
    			return false;
    		}
     
    		boolean numericFlag = true;
    		for (int i = 0; i < source.length(); i++) {
    			if (!Character.isDigit(source.charAt(i))) {
    				numericFlag = false;
    			} 		
    		}
     
    		return numericFlag;
    	}
     
     
    	/**
    	 * Calculates the Luhn check digit for the passed parameter.
    	 * For further details on the Luhn algorithm refer to http://en.wikipedia.org/wiki/Luhn_algorithm
    	 * 
    	 * @param source a string containing only numeric characters
    	 * @since 1.0
    	 * @return a single digit checksum calculated from the numerical value within source.
    	 * If source is not a numeric string or the check digit could not be calculated then a null value is returned.
    	 */
    	public String getCheckDigit(String source) {
    		// Null strings or non-numerical values are not valid
    		if (!(isNumeric(source))) {
    			return null;
    		}
     
    		// Keep a running tally of the check digit
    		int checkDigitSum = 0;
    		String luhnCheckDigit = null;
     
    		// Examine each digit in reverse order
    		for (int i=0; i < source.length(); i++) {
    			int examineDigit = Integer.parseInt(Character.toString(source.charAt(source.length() - 1 - i)));
     
    			// Double the value of every second digit
    			if (i % 2 == 0) {
    				examineDigit *= 2;
    			}
     
    			// Add double digits together within number array, e.g. the number 14 is treated as 1+4.
    			int singleDigit = 0;
    			String combineDigits = Integer.toString(examineDigit);
    			for (int j=0; j < combineDigits.length(); j++) {
    				singleDigit += Integer.parseInt(Character.toString(combineDigits.charAt(j)));
    			}
     
    			// Add the derived digit to the check digit tally
    			checkDigitSum += singleDigit;
    		}
     
    		// Work out which digit would make the checkDigitSum divisible by 10
    		for (int loopCount=0; loopCount < 10; loopCount++) {
    			if ((checkDigitSum + loopCount) % 10 == 0) {
    				luhnCheckDigit = Integer.toString(loopCount);
    				break;
    			}
    		}
     
    		return luhnCheckDigit;
    	}
     
    	/**
    	 * Validates that the check digit for source validates properly using the Luhn algorithm.
    	 * For further details on the Luhn algorithm refer to http://en.wikipedia.org/wiki/Luhn_algorithm
    	 * 
    	 * @param source a string containing only numeric characters
    	 * @since 1.0
    	 * @return true - check digit validates correctly against the algorithm.
    	 * false - the calculated check digit does not match that contained within source, or source is not a numeric string
    	 */
    	public boolean isCheckDigitValid(String source) {
    		// Null strings or non-numerical values are not valid
    		if (!(isNumeric(source)))
    			return false;
     
    		// A check digit cannot be validated against itself
    		if (source.length() < 2)
    			return false;
     
    		String prefix = source.substring(0, source.length() - 1);
    		String suffix = source.substring(source.length() - 1);
     
    		return (suffix.equals(getCheckDigit(prefix)));
    	}
    }

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.