Java 使用 Luhn 算法检查信用卡有效性

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20740444/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 03:58:47  来源:igfitidea点击:

Check Credit Card Validity using Luhn Algorithm

javaarraysvalidationcredit-cardluhn

提问by user3126388

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

我尝试使用 Luhn 算法检查信用卡的验证,其工作方式如下:

  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.

  1. 从右到左每第二个数字加倍。如果一位数加倍得到两位数,则将两位数相加得到一位数。

    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. 现在将步骤 1 中的所有个位数数字相加。

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

  3. 将卡号中从右到左的奇数位中的所有数字相加。

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

  4. 将步骤 2 和步骤 3 的结果相加。

    37 + 38 = 75

  5. 如果步骤 4 的结果能被 10 整除,则卡号有效;否则无效。例如号码4388576018402626无效,但号码4388576018410707有效。

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.

简而言之,我的程序始终显示对我输入的所有内容有效。即使它是一个有效数字并且 sumOfOddPlace 和 sumOfDoubleEvenPlace 方法的结果等于零。
任何帮助表示赞赏。

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

回答by Boris the Spider

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

有两种方法可以将您拆分intList<Integer>

  1. Use %10as you are using and store it into a List
  2. Convert to a Stringand then take the numeric values
  1. 使用时%10使用并将其存储在List
  2. 转换为 aString然后取数值

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

回答by sebii

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 arraythe individual digits:

为简单起见,我将使用 5 位卡号。假设您的卡号是12345;如果我正确阅读了代码,您将存储在array单个数字中:

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

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

既然你已经有了数字,sumOfOddPlace你应该做一些类似的事情

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:

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

回答by Meno Hochschild

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

谷歌和维基百科是你的朋友。我会使用 int-array 而不是 long-array。在维基百科上发布了以下java代码(连同Luhn算法的详细解释):

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

回答by Piyush

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

这是我仅用于 16 位信用卡号的 luhn 算法实现

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.

如果您想在任何数字上使用它,请将所有 16 替换为您输入的数字长度。

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

它适用于问题中给出的签证号码。(我测试过)

回答by Nicholas Ng

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

链接参考:https: //github.com/jduke32/gnuc-credit-card-checker/blob/master/CCCheckerPro/src/com/gnuc/java/ccc/Luhn.java

回答by DigiDuncan

Here's my implementation of the Luhn Formula.

这是我对 Luhn 公式的实现。

/**
 * 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 cwhich I get from a Scanner and store in card, and for cnI pass in checkNumber = card.charAt( (card.length() - 1) );.

我传入c我从扫描仪获取并存储的卡card,因为cn我传入了checkNumber = card.charAt( (card.length() - 1) );

回答by Dun

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

好的,这可以通过将类型转换为字符串和一些 Java 8 的东西来解决。不要忘记数字和代表数字的字符是不一样的。'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:

您现在可以使用此方法来执行 luhn 算法:

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

回答by nicoladc89

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

回答by user3328528

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

回答by user2362840

I took a stab at this with Java 8:

我用 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.

来自 Apache 的 commons-validator。