java - 在java中循环信用卡验证

标签 java loops if-statement

我是一名计算机科学入门类(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/

相关文章:

java - Spring MVC 如何禁止数据绑定(bind)到 ModelAttribute?

Java类加载器,加载的类类依赖怎么办?

Java GUI 在调整大小之前显示空白

java - 在 Java 中使用 for 循环测试天数

python while循环意外行为

java - 了解嵌套循环和类

javascript - if 的多个条件

java - 试图理解 3 个嵌套的 if 语句

java - 使用 MS Excel 2007 将 excel 文件中的数据转换为 xml

matlab - matlab中的三元运算符