循环使用java中的信用卡验证

Aro*_*rom 5 java loops if-statement

我是计算机科学入门课程的高中生.我们的任务如下:

信用卡号码的最后一位是校验位,可防止转录错误,例如单个数字错误或切换两位数字.以下方法用于验证实际的信用卡号,但为简单起见,我们将为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;
    }
}
Run Code Online (Sandbox Code Playgroud)

循环是我遇到的问题.无论何时编译,我总是以无限循环结束.但看起来一切都应该有效.它应该减少校验数字的值(不增加,所以我不会以10或更高的校验位数结束),然后将该数字添加回总和,直到总和可以被10整除,并且然后循环结束.循环的类型我使用错了吗?任何意见,将不胜感激.

Rad*_*def 2

你的问题是你的两个循环条件都涉及totalSum但你只改变了checkDigit

while (totalSum % 10 != 0)
{
    checkDigit--;
    if (totalSum % 10 == 0)
    {
        break;
    }
}
Run Code Online (Sandbox Code Playgroud)

您需要重新计算totalSum或更改基于 的条件checkDigit。如果您想像现在一样循环和递减,您将需要添加一个执行算法并每次调用它的方法。您概述类的方式使这非常不方便,因为您不转换数字。

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;
}
Run Code Online (Sandbox Code Playgroud)

现在你可以做类似的事情:

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];
}
Run Code Online (Sandbox Code Playgroud)

但您应该能够仅减去差异即可找到有效的校验位:

if (totalSum % 10 != 0) checkDigit -= totalSum % 10;
Run Code Online (Sandbox Code Playgroud)

或者类似的东西:

public void makeItValid() {
    int[] invalidNumbers = cardToNumbers(creditCardNumber);

    checkDigit = invalidNumbers[invalidNumbers.length - 1] -= totalSum % 10;
    totalSum = calcTotalSum(invalidNumbers);

    valid = true;
}
Run Code Online (Sandbox Code Playgroud)

一些旁白,

我建议将数字存储为字段并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
}
Run Code Online (Sandbox Code Playgroud)

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);
}
Run Code Online (Sandbox Code Playgroud)

我想这或多或少是在为你做功课,但我相信你可以从中学习。