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
How do I implement the Luhn algorithm?
提问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 for
loop, 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 i
for 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 String
from 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.print
,input.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 值。