Validate credit card number using luhn algorithm

2019-03-29 13:02发布

问题:

I have a question regarding the following programming assignment.

Credit card numbers follow certain patterns. A credit card must have between 13 and 16 digits. It must start with:

• 4 for Visa cards

• 5 for Master cards

• 37 for American Express cards

In 1954, Hans Luhn of IBM proposed an algorithm for validating credit card numbers. The algorithm is useful to determine if a card number is entered correctly or if a credit card is scanned correctly by a scanner. Almost all credit card numbers are generated following this validity check, commonly know as the Luhn check or the Modulus 10 check, which can be described as follows. For illustration, consider the card number 4388576018402625.

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

2 x 2 = 4

2 x 2 = 4

4 x 2 = 8

1 x 2 = 2

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

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

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

4 x 2 = 8

  1. Add all the single digit numbers from step 1 4 + 4 +8 + 2 +3 + 1 + 7 + 8 = 37

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

5 + 6 + 0 + 8 + 0 + 7 + 8 + 3 = 37

  1. Sum the results from step 2 and step 3 37 + 37 = 74

  2. If the result from step is divisible by 10, the card number is valid; otherwise, it’s invalid. For example, the number 4388576018402625 is invalid, but the number 4388576018410707 is a valid Visa card; the number 6011000593748745 is invalid, but the number 6011000593748746 is a valid Discover card.

I tried to solve it as shown in the following code:

import java.util.Scanner;

public class CreditCardValidation {

    public static boolean isValid(long number) {

        int total = sumOfDoubleEvenPlace(number) + sumOfOddPlace(number);


        if ((total % 10 == 0) && (prefixMatched(number, 1) == true) && (getSize(number)>=13 ) && (getSize(number)<=16 )) {
            return true;
        } else {
            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 number) {
        int result = 0;

        while (number > 0) {
            result += (int) (number % 10);
            number = number / 100;
        }

        return result;
    }

    public static int sumOfDoubleEvenPlace(long number) {

        int result = 0;
        long temp = 0;

        while (number > 0) {
            temp = number % 100;
            result += getDigit((int) (temp / 10) * 2);
            number = number / 100;
        }

        return result;
    }

    public static boolean prefixMatched(long number, int d) {

        if ((getPrefix(number, d) == 4)
                || (getPrefix(number, d) == 5)
                || (getPrefix(number, d) == 3)) {

            if (getPrefix(number, d) == 3) {
                System.out.println("\nVisa Card ");
            } else if (getPrefix(number, d) == 5) {
                System.out.println("\nMaster Card ");
            } else if (getPrefix(number, d) == 3) {
                System.out.println("\nAmerican Express Card ");
            }

            return true;

        } else {

            return false;

        }
    }

    public static int getSize(long d) {

        int count = 0;

        while (d > 0) {
            d = d / 10;

            count++;
        }

        return count;

    }

    public static long getPrefix(long number, int k) {

        if (getSize(number) < k) {
            return number;
        } else {

            int size = (int) getSize(number);

            for (int i = 0; i < (size - k); i++) {
                number = number / 10;
            }

            return number;

        }

    }

    public static void main(String[] args) {

        Scanner sc = new Scanner(System.in);

        System.out.print("Enter a credit card number as a long integer: ");

        long input = sc.nextLong();


        if (isValid(input) == true) {
            System.out.println("\n" + input + " is Valid. ");
        } else {
            System.out.println("\n" + input + " is Invalid. ");
        }

    }
} 

My question is how can I use an array to store the credit card number instead of using a long number.

回答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;
}


回答2:

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)



回答3:

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) );.



回答4:

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);
            }


回答5:

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;
}
}