11

I tried to check the validation of credit card using Luhn algorithm, which works as the following steps:

  1. Double every second digit from right to left. If doubling of a digit results in a two-digit number, add up the two digits to get a single-digit number.

    2 * 2 = 4

    2 * 2 = 4

    4 * 2 = 8

    1 * 2 = 2

    6 * 2 = 12 (1 + 2 = 3)

    5 * 2 = 10 (1 + 0 = 1)

    8 * 2 = 16 (1 + 6 = 7)

    4 * 2 = 8

  2. Now add all single-digit numbers from Step 1.

    4 + 4 + 8 + 2 + 3 + 1 + 7 + 8 = 37

  3. Add all digits in the odd places from right to left in the card number.

    6 + 6 + 0 + 8 + 0 + 7 + 8 + 3 = 38

  4. Sum the results from Step 2 and Step 3.

    37 + 38 = 75

  5. If the result from Step 4 is divisible by 10, the card number is valid; otherwise, it is invalid. For example, the number 4388576018402626 is invalid, but the number 4388576018410707 is valid.

Simply, my program always displays valid for everything that I input. Even if it's a valid number and the result of sumOfOddPlace and sumOfDoubleEvenPlace methods are equal to zero.
Any help is appreciated.

import java.util.Scanner;
public class CreditCardValidation {
      public static void main(String[] args) {
     Scanner in = new Scanner(System.in);
        int count = 0;
        long array[] = new long [16];
       do
       {
        count = 0;
       array = new long [16];
        System.out.print("Enter your Credit Card Number : ");
        long number = in.nextLong();
        for (int i = 0; number != 0; i++) {
        array[i] = number % 10;
        number = number / 10;
        count++;
        }
       }
        while(count < 13); 
        if ((array[count - 1] == 4) || (array[count - 1] == 5) || (array[count - 1] == 3 && array[count - 2] == 7)){
            if (isValid(array) == true) {
                System.out.println("\n The Credit Card Number is Valid. ");
        } else {
            System.out.println("\n The Credit Card Number is Invalid. ");
        }
        } else{
          System.out.println("\n The Credit Card Number is Invalid. ");
        }
    }

    public static boolean isValid(long[] array) {
        int total = sumOfDoubleEvenPlace(array) + sumOfOddPlace(array);        
        if ((total % 10 == 0)) {
         for (int i=0; i< array.length; i++){
            System.out.println(array[i]);}
            return true;
        } else {
          for (int i=0; i< array.length; i++){
            System.out.println(array[i]);}
            return false;
        }
    }

    public static int getDigit(int number) {
        if (number <= 9) {
            return number;
        } else {
            int firstDigit = number % 10;
            int secondDigit = (int) (number / 10);
            return firstDigit + secondDigit;
        }
    }

    public static int sumOfOddPlace(long[] array) {
        int result = 0;
        for (int i=0; i< array.length; i++)
        {
        while (array[i] > 0) {
            result += (int) (array[i] % 10);
            array[i] = array[i] / 100;
         }}
         System.out.println("\n The sum of odd place is " + result);
        return result;
    }

    public static int sumOfDoubleEvenPlace(long[] array) {
        int result = 0;
        long temp = 0;
        for (int i=0; i< array.length; i++){
        while (array[i] > 0) {
             temp = array[i] % 100;
             result += getDigit((int) (temp / 10) * 2);
            array[i] = array[i] / 100;
           }
        }
        System.out.println("\n The sum of double even place is " + result);
        return result;
    }
     }
user3126388
  • 171
  • 2
  • 2
  • 5
  • 2
    You could use a `String`... – Oliver Charlesworth Dec 22 '13 at 02:51
  • When I tried 4242424242424242 as input, your program says "The Credit Card Number is Valid", which is expected I suppose. Could you tell us the specific input(s) which cause your program to give an unexpected output? – aquaraga Dec 23 '13 at 09:26
  • Also, the number that you gave "4388576018410707" also is mentioned as valid. – aquaraga Dec 23 '13 at 09:33
  • I am sorry I meant it always gives "The Credit Card Number is Valid" if the number start with 4, 5 or 37. It doesn't follow the second condition which is related to the total of sumOfOddPlace and sumOfDoubleEvenPlace methods. – user3126388 Dec 23 '13 at 09:38
  • Okay, so the problem is that your program is treating all card numbers as VALID and not INVALID. So, please correct the question. Secondly, your program always prints that "The sum of double even place is 0" and "The sum of odd place is 0" - so a little debugging would help. One last thing; why do you always divide by 100. I think that is one of the culprits. – aquaraga Dec 23 '13 at 09:41

13 Answers13

25

You can freely import the following code:

public class Luhn
{
    public static boolean Check(String ccNumber)
    {
            int sum = 0;
            boolean alternate = false;
            for (int i = ccNumber.length() - 1; i >= 0; i--)
            {
                    int n = Integer.parseInt(ccNumber.substring(i, i + 1));
                    if (alternate)
                    {
                            n *= 2;
                            if (n > 9)
                            {
                                    n = (n % 10) + 1;
                            }
                    }
                    sum += n;
                    alternate = !alternate;
            }
            return (sum % 10 == 0);
    }
}

Link reference: https://github.com/jduke32/gnuc-credit-card-checker/blob/master/CCCheckerPro/src/com/gnuc/java/ccc/Luhn.java

Christoph Leiter
  • 9,147
  • 4
  • 29
  • 37
Nicholas Ng
  • 1,428
  • 18
  • 23
  • This code does not allow barcode terminates on 0 (zero) like '1000000401330'. I had found this code and works fine: http://www.admfactory.com/luhn-algorithm-implementation-in-java/ – deldev Jun 01 '17 at 18:45
  • 1
    Just for the record, this **does work** with codes ending in 0, including the one @dellasavia mentions, **given that the input string consists only of digits** (no whitespace, letters or special characters). You can test it by yourself against valid card numbers such as the ones listed [here](https://www.datatrans.ch/showcase/test-cc-numbers) or [here](https://www.paypalobjects.com/en_GB/vhelp/paypalmanager_help/credit_card_numbers.htm) – Sam May 08 '18 at 18:27
  • @Sam 1st link to www.datatrans.ch is broken. – huha Jan 05 '23 at 07:36
  • The card number 76009244561 Dankort (PBS) from 2nd link doesn't work. Should be 76009244567. See also [here](https://stackoverflow.com/a/5376991/1051244) – huha Jan 05 '23 at 07:38
  • @huha this one works https://docs.datatrans.ch/docs/testing-credentials – Sam Jan 05 '23 at 19:59
9

Google and Wikipedia are your friends. Instead of long-array I would use int-array. On Wikipedia following java code is published (together with detailed explanation of Luhn algorithm):

   public static boolean check(int[] digits) {
     int sum = 0;
     int length = digits.length;
     for (int i = 0; i < length; i++) {

       // get digits in reverse order
       int digit = digits[length - i - 1];

       // every 2nd number multiply with 2
       if (i % 2 == 1) {
           digit *= 2;
       }
       sum += digit > 9 ? digit - 9 : digit;
     }
     return sum % 10 == 0;
   }

You should work on your input processing code. I suggest you to study following solution:

public static void main(String[] args) {
    Scanner in = new Scanner(System.in);
    boolean repeat;
    List<Integer> digits = new ArrayList<Integer>();

    do {
        repeat = false;
        System.out.print("Enter your Credit Card Number : ");
        String input = in.next();

        for (int i = 0; i < input.length(); i++) {
            char c = input.charAt(i);
            if (c < '0' || c > '9') {
                repeat = true;
                digits.clear();
                break;
            } else {
                digits.add(Integer.valueOf(c - '0'));
            }
        }
    } while (repeat);

    int[] array = new int[digits.size()];
    for (int i = 0; i < array.length; i++) {
        array[i] = Integer.valueOf(digits.get(i));
    }
    boolean valid = check(array);
    System.out.println("Valid: " + valid);
}
Meno Hochschild
  • 42,708
  • 7
  • 104
  • 126
  • Just a remark: The line "array = new long [16];" inside do-loop cannot be okay because you are resetting the array every time. – Meno Hochschild Dec 23 '13 at 10:12
  • I have checked the proposed solution for your example credit card numbers 4388576018402626 (invalid) and 4388576018410707 (valid). – Meno Hochschild Dec 23 '13 at 10:49
  • I'd be interested in your thoughts on http://stackoverflow.com/questions/37352477/are-there-any-valid-credit-numbers-that-are-initial-substrings-of-other-valid-cr – Peter Alfvin May 20 '16 at 17:36
4

I took a stab at this with Java 8:

public static boolean luhn(String cc) {
    final boolean[] dbl = {false};
    return cc
            .chars()
            .map(c -> Character.digit((char) c, 10))
            .map(i -> ((dbl[0] = !dbl[0])) ? (((i*2)>9) ? (i*2)-9 : i*2) : i)
            .sum() % 10 == 0;
}

Add the line

            .replaceAll("\\s+", "")

Before

            .chars()

If you want to handle whitespace.

Seems to produce identical results to

return LuhnCheckDigit.LUHN_CHECK_DIGIT.isValid(cc);

From Apache's commons-validator.

user2362840
  • 183
  • 7
1

There are two ways to split up your int into List<Integer>

  1. Use %10 as you are using and store it into a List
  2. Convert to a String and then take the numeric values

Here are a couple of quick examples

public static void main(String[] args) throws Exception {
    final int num = 12345;
    final List<Integer> nums1 = splitInt(num);
    final List<Integer> nums2 = splitString(num);
    System.out.println(nums1);
    System.out.println(nums2);
}

private static List<Integer> splitInt(int num) {
    final List<Integer> ints = new ArrayList<>();
    while (num > 0) {
        ints.add(0, num % 10);
        num /= 10;
    }
    return ints;
}

private static List<Integer> splitString(int num) {
    final List<Integer> ints = new ArrayList<>();
    for (final char c : Integer.toString(num).toCharArray()) {
        ints.add(Character.getNumericValue(c));
    }
    return ints;
}
Boris the Spider
  • 59,842
  • 6
  • 106
  • 166
1

I'll use 5 digit card numbers for simplicity. Let's say your card number is 12345; if I read the code correctly, you store in array the individual digits:

array[] = {1, 2, 3, 4, 5}

Since you already have the digits, in sumOfOddPlace you should do something like

public static int sumOfOddPlace(long[] array) {
    int result = 0;
    for (int i = 1; i < array.length; i += 2) {
        result += array[i];
    }
    return result;
}

And in sumOfDoubleEvenPlace:

public static int sumOfDoubleEvenPlace(long[] array) {
    int result = 0;
    for (int i = 0; i < array.length; i += 2) {
        result += getDigit(2 * array[i]);
    }
    return result;
}
sebii
  • 506
  • 2
  • 6
1

this is the luhn algorithm implementation which I use for only 16 digit Credit Card Number

if(ccnum.length()==16){
    char[] c = ccnum.toCharArray();
    int[] cint = new int[16];
    for(int i=0;i<16;i++){
        if(i%2==1){
            cint[i] = Integer.parseInt(String.valueOf(c[i]))*2;
            if(cint[i] >9)
                cint[i]=1+cint[i]%10;
        }
        else
            cint[i] = Integer.parseInt(String.valueOf(c[i]));
    }
    int sum=0;
    for(int i=0;i<16;i++){
        sum+=cint[i];
    }
    if(sum%10==0)
        result.setText("Card is Valid");
    else
        result.setText("Card is Invalid");
}else
    result.setText("Card is Invalid");

If you want to make it use on any number replace all 16 with your input number length.

It will work for Visa number given in the question.(I tested it)

Piyush
  • 1,528
  • 2
  • 24
  • 39
1

Here's my implementation of the Luhn Formula.

/**
 * Runs the Luhn Equation on a user inputed CCN, which in turn
 * determines if it is a valid card number.
 * @param c A user inputed CCN.
 * @param cn The check number for the card.
 * @return If the card is valid based on the Luhn Equation.
 */
public boolean luhn (String c, char cn)
{
    String card = c;
    String checkString = "" + cn;
    int check = Integer.valueOf(checkString);

    //Drop the last digit.
    card = card.substring(0, ( card.length() - 1 ) );

    //Reverse the digits.
    String cardrev = new StringBuilder(card).reverse().toString();

    //Store it in an int array.
    char[] cardArray = cardrev.toCharArray();
    int[] cardWorking = new int[cardArray.length];
    int addedNumbers = 0;

    for (int i = 0; i < cardArray.length; i++)
    {
        cardWorking[i] = Character.getNumericValue( cardArray[i] );
    }

    //Double odd positioned digits (which are really even in our case, since index starts at 0).

    for (int j = 0; j < cardWorking.length; j++)
    {
        if ( (j % 2) == 0)
        {
            cardWorking[j] = cardWorking[j] * 2;
        }
    }

    //Subtract 9 from digits larger than 9.

    for (int k = 0; k < cardWorking.length; k++)
    {
        if (cardWorking[k] > 9)
        {
            cardWorking[k] = cardWorking[k] - 9;
        }
    }

    //Add all the numbers together.
    for (int l = 0; l < cardWorking.length; l++)
    {
        addedNumbers += cardWorking[l];
    }

    //Finally, check if the number we got from adding all the other numbers
    //when divided by ten has a remainder equal to the check number.
    if (addedNumbers % 10 == check)
    {
        return true;
    }
    else
    {           
        return false;
    }
}

I pass in the card as c which I get from a Scanner and store in card, and for cn I pass in checkNumber = card.charAt( (card.length() - 1) );.

DigiDuncan
  • 131
  • 1
  • 2
  • 11
1

Okay, this can be solved with a type conversions to string and some Java 8 stuff. Don't forget numbers and the characters representing numbers are not the same. '1' != 1

public static int[] longToIntArray(long cardNumber){

return Long.toString(cardNumber).chars()
    .map(x -> x - '0') //converts char to int 
    .toArray();  //converts to int array
}

You can now use this method to perform the luhn algorithm:

  public static int luhnCardValidator(int cardNumbers[]) {
                int sum = 0, nxtDigit;
                for (int i = 0; i<cardNumbers.length; i++) {
                    if (i % 2 == 0) 
                      nxtDigit  = (nxtDigit > 4) ? (nxtDigit * 2 - 10) + 1 : nxtDigit * 2;
                    sum += nxtDigit;
                }
                return (sum % 10);
            }
Dun
  • 11
  • 1
  • 3
0
private static int luhnAlgorithm(String number){
    int n=0;
    for(int i = 0; i<number.length(); i++){
        int x = Integer.parseInt(""+number.charAt(i));
        n += (x*Math.pow(2, i%2))%10;
        if (x>=5 && i%2==1) n++;
    }
    return n%10;
}
  • 2
    Code dumps do not make for good answers. You should explain *how* and *why* this solves their problem and why this answer is better than the other established answers we already have. I recommend reading, "[How do I write a good answer?"](http://stackoverflow.com/help/how-to-answer) – John Conde Oct 17 '17 at 18:22
0
public class Creditcard {

    public static void main(String args[]){
        Scanner sc=new Scanner(System.in);
        String cardno = sc.nextLine();

        if(checkType(cardno).equals("U")) //checking for unknown type
          System.out.println("UNKNOWN");
        else
          checkValid(cardno); //validation 
}

private static String checkType(String S)
{
    int AM=Integer.parseInt(S.substring(0,2));
    int D=Integer.parseInt(S.substring(0,4)),d=0;
    for(int i=S.length()-1;i>=0;i--)
    {
        if(S.charAt(i)==' ')
            continue;
        else
            d++;
    }
    if((AM==34 || AM==37) && d==15)
        System.out.println("AMEX");
    else if(D==6011 && d==16)
        System.out.println("Discover");
    else if(AM>=51 && AM<=55 && d==16)
        System.out.println("MasterCard");
    else if(((S.charAt(0)-'0')==4)&&(d==13 || d==16)) 
        System.out.println("Visa");
    else
        return "U";
    return "";
}

private static void checkValid(String S) // S--> cardno
{
    int i,d=0,sum=0,card[]=new int[S.length()];

    for(i=S.length()-1;i>=0;i--)
    {
        if(S.charAt(i)==' ')
            continue;
        else
            card[d++]=S.charAt(i)-'0';
    }

    for(i=0;i<d;i++)
    {
        if(i%2!=0)
        {
            card[i]=card[i]*2;
            if(card[i]>9)
                sum+=digSum(card[i]);
            else
                sum+=card[i];
        }
        else
            sum+=card[i];
    }
    if(sum%10==0)
        System.out.println("Valid");
    else    
        System.out.println("Invalid");

}

public static int digSum(int n)
{
    int sum=0;
    while(n>0)
    {
        sum+=n%10;
        n/=10;
    }
    return sum;
}
}
Taslim Oseni
  • 6,086
  • 10
  • 44
  • 69
0
public class LuhnAlgorithm {

/**
 * Returns true if given card number is valid
 *
 * @param cardNum Card number
 * @return true if card number is valid else false
 */
private static boolean checkLuhn(String cardNum) {
    int cardlength = cardNum.length();
    int evenSum = 0, oddSum = 0, sum;
    for (int i = cardlength - 1; i >= 0; i--) {
        System.out.println(cardNum.charAt(i));
        int digit = Character.getNumericValue(cardNum.charAt(i));
        if (i % 2 == 0) {
            int multiplyByTwo = digit * 2;
            if (multiplyByTwo > 9) {
                /* Add two digits to handle cases that make two digits after doubling */
                String mul = String.valueOf(multiplyByTwo);
                multiplyByTwo = Character.getNumericValue(mul.charAt(0)) + Character.getNumericValue(mul.charAt(1));
            }
            evenSum += multiplyByTwo;
        } else {
            oddSum += digit;
        }
    }
    sum = evenSum + oddSum;
    if (sum % 10 == 0) {
        System.out.println("valid card");
        return true;
    } else {
        System.out.println("invalid card");
        return false;
    }

}

public static void main(String[] args) {
    String cardNum = "8112189875";
    System.out.println(checkLuhn(cardNum));
}

}

Hope it may works.

parub
  • 129
  • 1
  • 5
0

Here is the implementation of Luhn algorithm.

public class LuhnAlgorithm {

/**
 * Returns true if given card number is valid
 *
 * @param cardNum Card number
 * @return true if card number is valid else false
 */
private static boolean checkLuhn(String cardNum) {
    int cardlength = cardNum.length();
    int evenSum = 0, oddSum = 0, sum;
    for (int i = cardlength - 1; i >= 0; i--) {
        System.out.println(cardNum.charAt(i));
        int digit = Character.getNumericValue(cardNum.charAt(i));
        if (i % 2 == 0) {
            int multiplyByTwo = digit * 2;
            if (multiplyByTwo > 9) {
                /* Add two digits to handle cases that make two digits after doubling */
                String mul = String.valueOf(multiplyByTwo);
                multiplyByTwo = Character.getNumericValue(mul.charAt(0)) + Character.getNumericValue(mul.charAt(1));
            }
            evenSum += multiplyByTwo;
        } else {
            oddSum += digit;
        }
    }
    sum = evenSum + oddSum;
    if (sum % 10 == 0) {
        System.out.println("valid card");
        return true;
    } else {
        System.out.println("invalid card");
        return false;
    }

}

public static void main(String[] args) {
    String cardNum = "4071690065031703";
    System.out.println(checkLuhn(cardNum));
}

}
parub
  • 129
  • 1
  • 5
0

const options = {
  method: 'GET',
  headers: {Accept: 'application/json', 'X-Api-Key': '[APIkey]'}
};

fetch('https://api.epaytools.com/Tools/luhn?number=[CardNumber]&metaData=true', options)
  .then(response => response.json())
  .then(response => console.log(response))
  .catch(err => console.error(err));
Ian Gibs
  • 11
  • 2
  • This is a JS code sample of an API method to check a given card number against the Luhn Algorithm. The response of this method can also be made to provide general information about the card (such as brand, country issued in, issuing bank and more). All you have to do is register with the provider - [PCI Booking][2], to use this method. While they are a paid service, they also offer free accounts where you can perform these types of actions. – Ian Gibs Aug 16 '22 at 16:34