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

时间:2013-11-23 23:04:47

标签: 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;
    }
}

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

4 个答案:

答案 0 :(得分:2)

您的问题是,您的两个循环条件都涉及totalSum,但您只需更改checkDigit

while (totalSum % 10 != 0)
{
    checkDigit--;
    if (totalSum % 10 == 0)
    {
        break;
    }
}

您需要重新计算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;
}

现在您可以执行以下操作:

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

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

答案 1 :(得分:0)

除非我遗漏了一些关于验证工作方式的重要信息,否则makeitvalid方法将无法按照您接近它的方式工作。

将构造函数中的所有内容提取到方法中更有意义(至少对我而言)。

boolean isValid(String cardNumber);

除了设置有效标志外,它将执行构造函数所做的所有操作。你的构造函数然后变成

public CreditCard(String pCreditCardNumber){
    valid = isValid(pCreditCardNumber);
}

然后找到哪些更改会使其有效,您的检查有效方法会执行类似

的操作
change the value of check digit
   if (isValid(Changed String))
        return checkdigit
   else
       continue
repeat until you either find one that works or until you determine that it can't work.

答案 2 :(得分:0)

这个程序很有活力。我没有添加太多的错误处理。您可以输入任何可被8整除的数字。

行动中的代码:

Enter a card number: 4358 9795
Number is valid?: true

Continue? (y/n): y

Enter a card number: 4358 9796
Number is valid?: false

Continue? (y/n): y

Enter a card number: 43-58 97-95
Number is valid?: true

Continue? (y/n): n

Exiting...

<强> CreditCardValidator.java

import java.text.ParseException;
import java.util.Scanner;

public class CreditCardValidator {
    Integer[] digits;

    public CreditCardValidator(String numberSequence) {
        parseNumber(numberSequence);
    }

    private void parseNumber(String numberSequence) {
        try {
            String sequence = numberSequence.replaceAll("[\\s-]+", "");

            int length = sequence.length();

            if (length % 8 != 0) {
                throw new IllegalArgumentException("Number length invalid.");
            }

            digits = new Integer[length];

            int pos = 0;
            for (Character c : sequence.toCharArray()) {
                if (Character.isDigit(c)) {
                    digits[pos++] = Character.getNumericValue(c);
                } else {
                    throw new ParseException("Invalid digit.", pos);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private boolean validateNumber() {
        int sum = 0;

        for (int i = digits.length - 1; i >= 0; i--) {
            if (i % 2 == 1) {
                sum += digits[i];
            } else {
                sum += NumberUtils.sumDigits(digits[i] * 2);
            }
        }

        return sum % 10 == 0;
    }

    public static void main(String[] args) {
        boolean stop = false;
        CreditCardValidator c;

        while (!stop) {
            System.out.print("Enter a card number: ");
            c = new CreditCardValidator(new Scanner(System.in).nextLine());
            System.out.println("Number is valid?: " + c.validateNumber());
            System.out.print("\nContinue? (y/n): ");

            if (new Scanner(System.in).next().charAt(0) == 'n') {
                stop = true;
            }

            System.out.println();
        }

        System.out.println("Exiting...");
        System.exit(0);
    }
}

我写了一个单独的数字求和实用程序:

public class NumberUtils {
    public static void main(String[] args) {
        for(int i = 0; i < 2000; i+=75) {
            System.out.printf("%04d: %02d\n", i, sumDigits(i));
        }
    }

    public static int sumDigits(int n) {
        if (n < 0)
            return 0;

        return sumDigitsRecursive(n, 0);
    }

    private static int sumDigitsRecursive(int n, int total) {
        if (n < 10)
            return total + n;
        else {
            return sumDigitsRecursive(n / 10, total + (n % 10));
        }
    }
}

答案 3 :(得分:0)

这些方面应该做的事情。你仍然需要自己实现一些方法。

public static void main(String[] args) {
    String creditCardNumber = readCreditCardNumber();
    String correctCreditCardNumber = getCorrectCreditCardNumber(creditCardNumber);

    if (creditCardNumber.equals(correctCreditCardNumber)) {
        System.out.println("Credit Card Valid");
    } else {
        System.out.println("Credit Card Invalid. Did you mean " + correctCreditCardNumber + "?");
    }
}

public static String getCorrectCreditCardNumber(String creditCardNumber) {
    int[] creditCardDigits = getCreditCardDigits(creditCardNumber);

    int sum = 0;
    for (int i = creditCardDigits.length - 2; i >= 0; i--) {
        if (isOdd(i)) {
            sum += creditCardDigits[i];
        } else {
            sum += digitSum(creditCardDigits[i] * 2);
        }
    }

    int last = creditCardDigits.length - 1;
    int remainder = sum % 10;
    if (remainder != 0) {
        creditCardDigits[last] = 10 - remainder;
    }

    return getCreditCardNumberAsString(creditCardDigits);
}