java 我如何实现 Luhn 算法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/26383926/
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-11-02 09:50:14  来源:igfitidea点击:

How do I implement the Luhn algorithm?

javaalgorithmluhn

提问by Pontus

I am trying to create a program to validate 10 to 12 digit long number sequences based on the luhn algorithm, but my program keeps on telling me that every number is invalid even though they're not.

我正在尝试创建一个程序来验证基于 luhn 算法的 10 到 12 位长数字序列,但我的程序一直告诉我每个数字都是无效的,即使它们不是。

This number should be valid, but my code doesn't think so: 8112189876

这个数字应该是有效的,但我的代码不这么认为: 8112189876

This number should not be valid, which my program agrees with, as it thinks every number is invalid: 8112189875

这个数字不应该是有效的,我的程序同意这一点,因为它认为每个数字都是无效的: 8112189875

Here is my code:

这是我的代码:

static void luhn(){
    System.out.print("Enter number to validate:\n");
    String pnr = input.nextLine();
    int length = pnr.length();
    int sum = 0;
    for (int i = 1, pos = length - 1; i < 10; i++, pos--){
        char tmp = pnr.charAt(pos);
        int num = tmp - 0
        int product;
        if (i % 2 != 0){
            product = num * 1;
        }
        else{
            product = num * 2;
        }
        if (product > 9)
            product -= 9;
        sum+= product;              
        boolean valid = (sum % 10 == 0);
        if (valid){
            System.out.print("Valid!\r");
        }
        else{
            System.out.print("Invalid!");
        }
    }
}

回答by Bharat

use org.apache.commons.validator.routines.checkdigit.LuhnCheckDigit.LUHN_CHECK_DIGIT.isValid(number)

利用 org.apache.commons.validator.routines.checkdigit.LuhnCheckDigit.LUHN_CHECK_DIGIT.isValid(number)

Maven Dependency:

Maven 依赖:

<dependency>
    <groupId>commons-validator</groupId>
    <artifactId>commons-validator</artifactId>
    <version>1.5.1</version>
</dependency>

回答by durron597

The first thing I see is that you have:

我看到的第一件事是你有:

int num = tmp - 0

You should instead have:

你应该有:

int num = tmp - '0';

Secondly, you should be validating your sum outsideof the forloop, because you only care about the sum after processing all the digits.

其次,您应该在循环之外验证您的总和for,因为您只关心处理所有数字后的总和。

Thirdly, you are starting from the end of the number, and you are not including the first number of your string. Why not use ifor both tasks?

第三,您从数字的末尾开始,并且不包括字符串的第一个数字。为什么不i用于这两个任务?

Resulting (working) method:

结果(工作)方法:

static void luhn(){
  System.out.print("Enter number to validate:\n");
  String pnr = input.nextLine();
  // this only works if you are certain all input will be at least 10 characters
  int extraChars = pnr.length() - 10;
  if (extraChars < 0) {
    throw new IllegalArgumentException("Number length must be at least 10 characters!");
  }
  pnr = pnr.substring(extraChars, 10 + extraChars);
  int sum = 0;
  // #3: removed pos
  for (int i = 0; i < pnr.length(); i++){
    char tmp = pnr.charAt(i);
    // #1: fixed the '0' problem
    int num = tmp - '0';
    int product;
    if (i % 2 != 0){
      product = num * 1;
    }
    else{
      product = num * 2;
    }
    if (product > 9)
      product -= 9;
    sum+= product;              
  }
  // #2: moved check outside for loop
  boolean valid = (sum % 10 == 0);
  if (valid){
    System.out.print("Valid!\r");
  }
  else{
    System.out.print("Invalid!");
  }
}


Stylistically, this method would be more useful if, instead of method signature

在风格上,如果,而不是方法签名,则此方法将更有用

static void luhn() {

it instead had method signature

它反而有方法签名

static boolean luhn(String input) {

This easily allows your code to get the Stringfrom ANY source (a file, hardcoded, etc.) and do anything with the result (print a message as yours does, or do something else). Obviously you would move the System.out.print, input.nextLine(), and if(valid)bits of code outside of this method.

这很容易让您的代码String从任何来源(文件、硬编码等)获取,并对结果执行任何操作(像您一样打印一条消息,或执行其他操作)。很明显,你会移动System.out.printinput.nextLine()以及if(valid)这种方法的代码之外的位。

Full refactored program:

完全重构的程序:

import java.util.Scanner;

public class Luhn {
  private static Scanner input;

  public static void main(String... args) {
    input = new Scanner(System.in);
    System.out.print("Enter number to validate:\n");
    String pnr = input.nextLine();
    boolean result = luhn(pnr);
    printMessage(result);
    input.close();
  }

  static boolean luhn(String pnr){
    // this only works if you are certain all input will be at least 10 characters
    int extraChars = pnr.length() - 10;
    if (extraChars < 0) {
      throw new IllegalArgumentException("Number length must be at least 10 characters!");
    }
    pnr = pnr.substring(extraChars, 10 + extraChars);
    int sum = 0;
    for (int i = 0; i < pnr.length(); i++){
      char tmp = pnr.charAt(i);
      int num = tmp - '0';
      int product;
      if (i % 2 != 0){
        product = num * 1;
      }
      else{
        product = num * 2;
      }
      if (product > 9)
        product -= 9;
      sum+= product;              
    }
    return (sum % 10 == 0);
  }

  private static void printMessage(boolean valid) {
    if (valid){
      System.out.print("Valid!\r");
    }
    else{
      System.out.print("Invalid!");
    }
  }
}

回答by Pintouch

I use this function in an app for checking card number validity :

我在应用程序中使用此功能检查卡号有效性:

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

Hope it helps,

希望能帮助到你,

回答by SeverityOne

If you use Java 10 or higher, you can use the following code:

如果您使用 Java 10 或更高版本,则可以使用以下代码:

public static boolean luhn(String s) {
    IntUnaryOperator sumDigits = n -> n / 10 + n % 10;
    var digits = s.chars()
                  .map(Character::getNumericValue)
                  .toArray();
    return IntStream.rangeClosed(1, digits.length)
                    .map(i -> digits.length - i)
                    .map(i -> i % 2 == 0 ? digits[i] : sumDigits.applyAsInt(digits[i] * 2))
                    .sum() % 10 == 0;
}

It's the functional approach to this algorithm.

这是该算法的功能方法。

回答by Sabih Ahmed

package randomNumGen;

public class JavaLuhnAlgorithm {

    public static void main(String[] args) {
        // TODO Auto-generated method stub




        validateCreditCardNumber("8112189876");
        String imei = "012850003580200";
        validateCreditCardNumber(imei);
    }

    private static void validateCreditCardNumber(String str) {

        int[] ints = new int[str.length()];
        for (int i = 0; i < str.length(); i++) {
            ints[i] = Integer.parseInt(str.substring(i, i + 1));
        }
        for (int i = ints.length - 2; i >= 0; i = i - 2) {
            int j = ints[i];
            j = j * 2;
            if (j > 9) {
                j = j % 10 + 1;
            }
            ints[i] = j;
        }
        int sum = 0;
        for (int i = 0; i < ints.length; i++) {
            sum += ints[i];
        }
        if (sum % 10 == 0) {
            System.out.println(str + " is a valid credit card number");
        } else {
            System.out.println(str + " is an invalid credit card number");
        }
    }

}

回答by sawprogramming

Here's some functions I wrote to both calculate the check digit for a given number and to verify a given number sequence and extract the number from it.

这是我编写的一些函数,用于计算给定数字的校验位并验证给定数字序列并从中提取数字。

To calculate the check digit for a given number:

要计算给定数字的校验位:

/**
 * Generates the check digit for a number using Luhn's algorithm described in detail at the following link:
 * https://en.wikipedia.org/wiki/Luhn_algorithm
 *
 * In short the digit is calculated like so:
 * 1. From the rightmost digit moving left, double the value of every second digit. If that value is greater than 9,
 *    subtract 9 from it.
 * 2. Sum all of the digits together
 * 3. Multiply the sum by 9 and the check digit will be that value modulo 10.
 *
 * @param number the number to get the Luhn's check digit for
 * @return the check digit for the given number
 */
public static int calculateLuhnsCheckDigit(final long number) {
    int     sum       = 0;
    boolean alternate = false;
    String  digits    = Long.toString(number);

    for (int i = digits.length() - 1; i >= 0; --i) {
        int digit = Character.getNumericValue(digits.charAt(i)); // get the digit at the given index
        digit = (alternate = !alternate) ? (digit * 2) : digit;  // double every other digit
        digit = (digit > 9)              ? (digit - 9) : digit;  // subtract 9 if the value is greater than 9
        sum += digit;                                            // add the digit to the sum
    }

    return (sum * 9) % 10;
}

To verify a sequence of digits using Luhn's algorithm and extract the number:

要使用 Luhn 算法验证数字序列并提取数字:

/**
 * Verifies that a given number string is valid according to Luhn's algorithm, which is described in detail here:
 * https://en.wikipedia.org/wiki/Luhn_algorithm
 *
 * In short, validity of the number is determined like so:
 * 1. From the rightmost digit (the check digit) moving left, double the value of every second digit. The check
 *    digit is not doubled; the first digit doubled is the one immediately to the left of the check digit. If that
 *    value is greater than 9, subtract 9 from it.
 * 2. Sum all of the digits together
 * 3. If the sum modulo 10 is equal to 0, then the number is valid according to Luhn's algorithm
 *
 * @param luhnsNumber the number string to verify and extract the number from
 * @return an empty Optional if the given string was not valid according to Luhn's algorithm
 *         an Optional containing the number verified by Luhn's algorithm if the given string passed the check
 */
public static Optional<Long> extractLuhnsNumber(final String luhnsNumber) {
    int     sum       = 0;
    boolean alternate = true;
    Long    number    = Long.parseLong(luhnsNumber.substring(0, luhnsNumber.length() - 1));

    for (int i = luhnsNumber.length() - 1; i >= 0; --i) {
        int digit = Character.getNumericValue(luhnsNumber.charAt(i)); // get the digit at the given index
        digit = (alternate = !alternate) ? (digit * 2) : digit;       // double every other digit
        digit = (digit > 9)              ? (digit - 9) : digit;       // subtract 9 if the value is greater than 9
        sum += digit;                                                 // add the digit to the sum
    }

    return (sum % 10 == 0) ? Optional.of(number) : Optional.empty();
}

回答by Hayk Nahapetyan

Newcomers to this post/question can check appropriate Wikipedia pagefor solution. Below is the Java code copy-pasted from there.

这篇文章/问题的新手可以查看适当的维基百科页面以获得解决方案。下面是从那里复制粘贴的 Java 代码。

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

回答by Tetramputechture

You should be subtracting '0' from tmp, not 0. Subtracting 0 returns the ASCII value, which you don't want.

您应该从 tmp 中减去“0”,而不是 0。减去 0 会返回您不想要的 ASCII 值。