我是一名计算机科学入门类(class)的高中生。我们的任务如下:
信用卡号的最后一位是校验位,它可以防止转录错误,例如单个数字错误或转换两个数字。以下方法用于验证实际的信用卡号码,但为简单起见,我们将针对 8 位而不是 16 位的号码进行描述:
- 从最右边的数字开始,形成每隔一个数字的总和。例如,如果信用卡号是 4358 9795,则总和为 5+7+8+3 = 23。
- 将上一步中未包含的每个数字加倍。将结果数字的所有数字相加。例如,对于上面给出的数字,将数字加倍,从倒数第二个数字开始,得到 18 18 10 8。将这些值中的所有数字相加得到 1+8+1+8+1+0+8 =27.
- 将前面两个步骤的总和相加。如果结果的最后一位为 0,则该数字有效。在我们的例子中,23 + 27 = 50,所以这个数字是有效的。
编写一个程序来实现这个算法。用户应提供一个 8 位数字,您应该打印出该数字是否有效。 如果无效,您应该打印出使数字有效的校验位的值。
除粗体部分外,我已完成所有操作。我的代码如下:
public class CreditCard
{
private String creditCardNumber;
private boolean valid;
private int checkDigit;
int totalSum;
/**
* Constructor for objects of class CreditCard
*/
public CreditCard(String pCreditCardNumber)
{
creditCardNumber = pCreditCardNumber;
checkDigit = Integer.parseInt(pCreditCardNumber.substring(creditCardNumber.length() - 1));
int sumOfDigits = checkDigit + Integer.parseInt(pCreditCardNumber.substring(6,7)) + Integer.parseInt(pCreditCardNumber.substring(3,4)) + Integer.parseInt(pCreditCardNumber.substring(1,2));
int dig7 = Integer.parseInt(pCreditCardNumber.substring(7,8));
int dig5 = Integer.parseInt(pCreditCardNumber.substring(5,6));
int dig3 = Integer.parseInt(pCreditCardNumber.substring(2,3));
int dig1 = Integer.parseInt(pCreditCardNumber.substring(0,1));
String string7 = Integer.toString(dig7);
int doubledDig7a = Integer.parseInt(string7.substring(0));
int doubledDig7b = 0;
if (dig7 * 2 >= 10)
{
doubledDig7a = Integer.parseInt(string7.substring(0));
doubledDig7b = 0;
}
String string5 = Integer.toString(dig5);
int doubledDig5a = Integer.parseInt(string7.substring(0));
int doubledDig5b = 0;
if (dig5 * 2 >= 10)
{
doubledDig5a = Integer.parseInt(string5.substring(0));
doubledDig5b = 0;
}
String string3 = Integer.toString(dig3);
int doubledDig3a = Integer.parseInt(string3.substring(0));
int doubledDig3b = 0;
if (dig3 * 2 >= 10)
{
doubledDig3a = Integer.parseInt(string3.substring(0));
doubledDig3b = 0;
}
String string1 = Integer.toString(dig1);
int doubledDig1a = Integer.parseInt(string1.substring(0));
int doubledDig1b = 0;
if (dig1 * 2 >= 10)
{
doubledDig1a = Integer.parseInt(string1.substring(0));
doubledDig1b = 0;
}
int doubleDigits = doubledDig1a + doubledDig1b + doubledDig3a + doubledDig3b + doubledDig5a + doubledDig5b + doubledDig7a + doubledDig7b;
totalSum = sumOfDigits + doubleDigits;
if (totalSum % 10 == 0)
{
valid = true;
}
else
{
valid = false;
}
}
public void makeItValid()
{
while (totalSum % 10 != 0)
{
checkDigit--;
if (totalSum % 10 == 0)
{
break;
}
}
}
public boolean isItValid()
{
return valid;
}
}
循环是我遇到的问题。每当编译时,我总是陷入无限循环。不过,看起来一切都应该有效。它应该减少校验位的值(而不是增加,所以我不会得到 10 或更高的校验位),然后将该数字加回总和,直到总和可以被 10 整除,并且然后循环结束。我使用的循环类型有误吗?任何意见,将不胜感激。
最佳答案
您的问题是您的两个循环条件都涉及totalSum
,但您只更改了checkDigit
。
while (totalSum % 10 != 0)
{
checkDigit--;
if (totalSum % 10 == 0)
{
break;
}
}
您需要重新计算 totalSum
或将条件更改为基于 checkDigit
。如果你想像你正在做的那样循环和递减,你需要添加一个执行算法的方法并每次调用它。您概述类(class)的方式使这非常不方便,因为您不转换数字。
public static int[] cardToNumbers(String cardText) {
// \D is regex for non-digits
cardText = cardText.replaceAll("\\D", "");
int[] cardNumbers = new int[cardText.length()];
// convert unicode to corresponding integers
for (int i = 0; i < cardText.length(); i++)
cardNumbers[i] = cardText.charAt(i) - '0';
return cardNumbers;
}
public static int calcTotalSum(int[] cardNumbers) {
int sum = 0;
/* "every other one" loops
*
* I recommend against the "mod 2 index" scheme
* i % 2 relies on the card number being even
* you can't have your code blow up with unusual inputs
*
*/
for (int i = cardNumbers.length - 1; i >= 0; i -= 2) {
sum += cardNumbers[i];
}
for (int i = cardNumbers.length - 2; i >= 0; i -= 2) {
int dig = cardNumbers[i] * 2;
while (dig > 0) {
sum += dig % 10;
dig /= 10;
}
}
return sum;
}
现在你可以这样做:
public void makeItValid() {
int[] invalidNumbers = cardToNumbers(creditCardNumber);
int sum = calcTotalSum(invalidNumbers);
while ((sum = calcTotalSum(invalidNumbers)) % 10 != 0)
invalidNumbers[invalidNumbers.length - 1]--;
totalSum = sum;
checkDigit = invalidNumbers[invalidNumbers.length - 1];
}
但是您应该能够只减去差值以找到有效的校验位:
if (totalSum % 10 != 0) checkDigit -= totalSum % 10;
或者类似的东西:
public void makeItValid() {
int[] invalidNumbers = cardToNumbers(creditCardNumber);
checkDigit = invalidNumbers[invalidNumbers.length - 1] -= totalSum % 10;
totalSum = calcTotalSum(invalidNumbers);
valid = true;
}
一些旁白,
我建议将数字存储为一个字段,并让 checkDigit
代表数组中的索引。这将简化您正在执行的一些操作。
我还建议不要像在您的 makeItValid
方法中那样在 IE 内部“静默”更改字段,除非这是分配的规范。我认为更好的形式是让“拥有”代码自己进行更改,这在外部更清晰。一个比较完整的实现看起来像这样:
public class CreditCard {
public static void main(String[] args) {
if (args.length == 0) return;
CreditCard card = new CreditCard(args[0]);
if (!card.isValidNumber()) {
card.setCheckDigit(card.getValidCheckDigit());
}
}
private final String cardText;
private final int[] cardDigits;
private final int cdIndex;
public CreditCard(String ct) {
cardDigits = cardToNumbers(cardText = ct);
if ((cdIndex = cardDigits.length - 1) < 0) {
throw new IllegalArgumentException("# had no digits");
}
}
public boolean isValidNumber() {
return calcTotalSum(cardDigits) % 10 == 0;
}
public void setCheckDigit(int dig) {
cardDigits[cdIndex] = dig;
}
public int getValidCheckDigit() {
int sum = calcTotalSum(cardDigits);
if (sum % 10 != 0) {
return cardNumbers[cdIndex] - sum % 10;
} else {
return cardNumbers[cdIndex];
}
}
// above static methods
}
IMO 的最佳形式是完全禁止创建信用卡对象,除非校验位有效。作为 OOP 原则,创建无效的信用卡应该没有意义。如果卡片无效,构造函数应该抛出异常,并有一个静态方法来更正数字。
我会做类似下面的事情(缩短):
public class CreditCard {
public CreditCard(String number) {
if (!validateCheckDigit(number)) {
throw new IllegalArgumentException("check digit failure");
}
}
}
public static void main(String[] args) {
String number = args[0];
CreditCard card = null;
boolean valid = false;
do {
try {
card = new CreditCard(number);
valid = true;
} catch (IllegalArgumentException e) {
number = CreditCard.correctCheckDigit(number);
}
} while (!valid);
}
我想这或多或少是在为你做功课,但我相信你可以从中学到东西。
关于java - 在java中循环信用卡验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20169017/