【问题标题】:credit card numbers need to be added without the dash需要添加信用卡号而不使用破折号
【发布时间】:2023-03-19 09:09:01
【问题描述】:

因此,信用卡号有效的条件之一是“前 4 位数字的总和必须比后 4 位数字的总和小 1”我认为问题可能在于将破折号计算为数字但不确定。规则 4 是所有数字的总和必须能被 4 整除,这似乎可行,但规则 5 不行。

int sum = ccNumber.chars().filter(Character::isDigit).map(Character::getNumericValue).sum();
        
        if(sum%4!=0){
            valid = false;
            errorCode = 4;
            return;
        }
        
// set values and for loop for fifth rule.
      
  String digits = ccNumber.replaceAll("[ˆ0-9]",""); 
        int firstfourdigits = 0;
        int lastfourdigits = 0;
       
        for(int i=0; i<4; i++)
            firstfourdigits = firstfourdigits + Character.getNumericValue(ccNumber.charAt(i));
        for (int i=0, m = ccNumber.length()-1; i<4; i++, m--)
            lastfourdigits = lastfourdigits + Character.getNumericValue(ccNumber.charAt(m));
            

// mutator for fifth rule
          
        if(lastfourdigits!= firstfourdigits -1){
            valid = false;
            errorCode = 5;
            return;
        }

抱歉,我迷路了,刚接触编码。

【问题讨论】:

  • 只有数字时才加。
  • 我犹豫是否将其标记为重复:stackoverflow.com/questions/875867/…
  • 似乎您正在使用 replaceAll 过滤您的输入,但您没有使用过滤后的输入。相反,您继续使用未过滤的输入。我已经更新了你的第五条规则的答案。
  • if(lastfourdigits!= firstfourdigits -1) 是倒退的。它检查 lastfourdigits 是否等于 firstfourdigits 小一。

标签: java


【解决方案1】:

编辑,因为你改变了你的问题。原始问题的原始答案位于底部

检查第一部分和最后一部分是否相差一个

你目前的代码很接近,但这里和那里都有一些错误。

  • 仅过滤掉数字:您用于过滤掉所有非数字字符的代码应该可以工作,但在您的以下代码中,您不再在循环中使用此过滤值。 p>

    firstfourdigits + Character.getNumericValue(ccNumber.charAt(i));
    

    这应该只使用带有数值的变量 => digits

    firstfourdigits = firstfourdigits + Character.getNumericValue(digits.charAt(i));
    
  • 第一组与最后一组的区别:此处的 -1 应替换为 +1。当您遇到此类检查的问题时,始终建议您尝试在一张纸上进行计算。让我们假设前 4 位数字的总和为 8,后 4 位数字的总和为 9。根据要求,这是一个有效数字,在您的支票中应该是 false if(lastfourdigits!= firstfourdigits -1)

    让我们填写:9 != 8-1 => 9 != 7 这样返回 false,并将其标记为无效。如果我们基于要求,您可以将前 4 位数字的总和应比后 4 位数字小一写为:firstfourdigits = lastfourdigits - 1。这在数学上与lastfourdigits = firstfourdigits + 1 相同。但是,在我们的检查中我们想知道这个检查是否不正确,所以我们应该将语句更改为:if(lastfourdigits != firstfourdigits + 1)

这 2 项更改应该会为您提供您所要求的结果。结合这些变化,我们来到下面的代码示例

    String digits = ccNumber.replaceAll("[ˆ0-9]", "");
    int firstfourdigits = 0;
    int lastfourdigits = 0;

    for (int i = 0; i < 4; i++)
        firstfourdigits = firstfourdigits + Character.getNumericValue(digits.charAt(i));
   
    for (int i = 0, m = ccNumber.length() - 1; i < 4; i++, m--) 
        lastfourdigits = lastfourdigits + Character.getNumericValue(digits.charAt(m));
    
      
    if(lastfourdigits!= firstfourdigits + 1){
        valid = false;
        errorCode = 5;
        return;
    }

其他建议

上面的示例应该适用于您的要求,并且基于您的代码。但是,可以对代码进行一些优化以使所有内容更具可读性

  • 在 for 循环中使用 方括号:为了更清楚地了解 for 循环中的内容和不包含的内容,我建议您使用大括号。虽然它们不是必需的,但它们会非常清楚地说明 for 循环中的内容和不存在的内容,并且可以防止在 for 循环中添加额外内容时难以发现的问题
  • 使用短符号进行加法:您可以使用短符号+=,而不是写firstfourdigits = firstfourdigits + Character.getNumericValue(digits.charAt(i));。这将采用等号左侧的值,并计算右侧该值的总和。 firstfourdigits += Character.getNumericValue(digits.charAt(i));

代码如下所示:

    String digits = ccNumber.replaceAll("[ˆ0-9]", "");
    int firstfourdigits = 0;
    int lastfourdigits = 0;

    for (int i = 0; i < 4; i++){
        firstfourdigits += Character.getNumericValue(digits.charAt(i));
    }

    for (int i = 0, m = ccNumber.length() - 1; i < 4; i++, m--) {
        lastfourdigits += Character.getNumericValue(digits.charAt(m));
    }
      
    if(lastfourdigits!= firstfourdigits + 1){
        valid = false;
        errorCode = 5;
        return;
    }

回答原始问题以计算所有数字的总和

您可以使用Character.isDigit(char)。为了简化 for 循环,您甚至可以使用流来获取总和

    int sum = ccNumber.chars().filter(Character::isDigit).map(Character::getNumericValue).sum();

    if (sum % 4 != 0) {
        valid = false;
        errorCode = 4;
        return;
    }
  • .chars():这将在提供的字符串中创建一个所有字符的流,以便我们可以一个一个地循环它们
  • .filter(Character::isDigit):这将过滤掉所有不是数字的字符
  • .map(Character::getNumericValue):这会将流从 Characters 映射到它们的数值,以便我们可以进一步使用它们
  • sum() 将计算我们当前在 Stream 中的数值的总和

【讨论】:

    【解决方案2】:

    差异始终是正值,例如4和5或5和4之间的差是一样的,即1。也就是说,你需要将减法的绝对值与1进行比较。

    因此,替换

    if(lastfourdigits!= firstfourdigits -1)
    

    if(Math.abs(lastfourdigits - firstfourdigits) != 1)
    

    您的代码中的另一个错误是您在循环中使用了ccNumber,而不是digits

    一些使您的代码更易于理解的建议:

    1. for (int i=0, m = digits.length()-1; i&lt;4; i++, m--) 替换为for (int m = digits.length() - 1; m &gt;= digits.length() - 4; m--)。请注意,我已经在这些语句中将ccNumber 替换为digits
    2. ccNumber.replaceAll("[^0-9]","") 替换为ccNumber.replaceAll("\\D", "")
    3. firstfourdigits = firstfourdigits + Character.getNumericValue(digits.charAt(i)) 替换为firstfourdigits += Character.getNumericValue(digits.charAt(i))。请注意,我已经在这些语句中将ccNumber 替换为digits
    4. 始终将 ifloop 语句的正文包含在 { } 中,即使正文中只有一个语句。

    演示:

    public class Main {
        public static void main(String[] args) {
            System.out.println(isValidOnDiffCriteria("1234-5678-9101-1213"));
            System.out.println(isValidOnDiffCriteria("1234-5678-9101-1235"));
            System.out.println(isValidOnDiffCriteria("1235-5678-9101-1234"));
        }
    
        static boolean isValidOnDiffCriteria(String ccNumber) {
            String digits = ccNumber.replaceAll("\\D", "");
            int firstfourdigits = 0;
            int lastfourdigits = 0;
    
            for (int i = 0; i < 4; i++) {
                firstfourdigits += Character.getNumericValue(digits.charAt(i));
            }
    
            for (int m = digits.length() - 1; m >= digits.length() - 4; m--) {
                lastfourdigits += Character.getNumericValue(digits.charAt(m));
            }
    
            if (Math.abs(lastfourdigits - firstfourdigits) != 1) {
                return false;
            }
            return true;
        }
    }
    

    输出:

    false
    true
    true
    

    【讨论】:

      【解决方案3】:

      试试上面的代码。应该是你问的。你不需要 try catch。

       static boolean isCardValid(String creditCard) {
          // group digits in a string array
          String[] cards = creditCard.split("-");
          int sumAll = 0;
          
          // for every group of digits we convert it to char[]
          for (String card : cards) {
              sumAll += sum(card.toCharArray());
          }
      
          int firstGroupOfDigits = sum(cards[0].toCharArray()) ;
          int lastGroupOfDigits = sum(cards[cards.length-1].toCharArray());
      
          if( firstGroupOfDigits == lastGroupOfDigits -1){
              if (sumAll % 4 == 0) {
                  return true;
              }
          }
          return false;
      }
      
      // sum the group of digits separated by "-"
      static int sum(char[] chr) {
          int sum = 0;
          for (char c : chr) {
              sum += Character.getNumericValue(c);
          }
          return sum;
      }
      

      【讨论】:

        【解决方案4】:

        嗯,你的程序还不错,据我所知只有一个问题,那就是你只是颠倒了第一组和最后一组所需的测试。我建议您确保将 valid 初始化为 true 作为默认值。然后如果没有设置任何错误代码,它将返回true。

        目前你有以下:

        if (lastfourdigits != firstfourdigits - 1) {
                    valid = false;
                    errorCode = 5;
        }
        

        但你需要的是这个

        if (lastfourdigits != firstfourdigits + 1) {
                    valid = false;
                    errorCode = 5;
        }
        

        您还有以下不必要的代码。

        String digits = ccNumber.replaceAll("[ˆ0-9]","");
        

        原因是您只是简单地使用ccNumber,从前四个字符的开头开始,从最后四个字符的末尾开始。通过这种方式,您不会遇到破折号,因此您不需要只获取数字。

        另一个建议是,一旦发现错误,就设置错误代码并立即返回。继续处理已经发现有缺陷的卡有什么用?

        其他注意事项和替代方法

        这可能不是作业的一部分,但我也会考虑以下几点:

        • 如果您的数字多于或少于 16 位怎么办?
        • 如果您有超过三个破折号给出超过四组数字怎么办。

        检查上述内容需要额外的逻辑,并且会使您的工作复杂化。但这是需要考虑的事情。下面演示了一种检查这些特定格式问题并报告它们的方法。这使用基本技术并避免流,以免重复不必要的操作。

        此示例根据发现的问题引发选择性错误。正如后面解释的那样,这些可以完全改变或消除。信用卡验证是一项任务,其中最直接的解决方案是最好的,并且应该需要较低的开销。

        首先,声明一个特殊的异常来捕获信用卡错误。

        class BadCreditCardException extends Exception {
            public BadCreditCardException(String message) {
                super(message);
            }
        }
        

        现在声明一些测试数据。

        String[] testData  = {
                "1234-4566-9292-0210",
                "1500-4009-2400-1600",
                "1500-4009-2400-160000",
                "1234-45669292-0210",
                "1@34-45-66-9292-0210",
                "1234-45B6-9292-0210",
                "1234-4566-9292-2234",
                "1234-4566-9292-021022",
                "1234-4566-9292-0210",
                "4567-4566-92!2-6835",
                "1234-4566-9292-0210",
                "1234-45+6-9292-0210",
                "1234-4566-92x2-0210",
                "1234-4566-9292-0210",
        };
        
        

        测试信用卡并报告错误。请注意,仅报告第一次遇到的错误。编号可能有多个错误。

        
        String fmt = "%-23s - %s%n";
        for(String card : testData) {
            try {
                validate(card);
                System.out.printf(fmt,card, "Valid");
            } catch (BadCreditCardException bce) {
                System.out.printf(fmt,card, bce.getMessage());
            }
        }
        

        以上打印。

        1234-4566-9292-0210     - Invalid credit card checksum
        1500-4009-2400-1600     - Valid
        1500-4009-2400-160000   - Non group of 4 digits
        1234-45669292-0210      - Insufficient or too may dashes
        1@34-45-66-9292-0210    - Insufficient or too may dashes
        1234-45B6-9292-0210     - Non digit found.
        1234-4566-9292-2234     - Valid
        1234-4566-9292-021022   - Non group of 4 digits
        1234-4566-9292-0210     - Invalid credit card checksum
        4567-4566-92!2-6835     - Non digit found.
        1234-4566-9292-0210     - Invalid credit card checksum
        1234-45+6-9292-0210     - Non digit found.
        1234-4566-92x2-0210     - Non digit found.
        1234-4566-9292-0210     - Invalid credit card checksum
        

        解释

        验证方法。该方法的工作原理如下。

        • 使用破折号(-) 作为分隔符将卡片分组。
        • 如果没有四个组,则抛出异常。
        • 否则,按如下方式对每个组求和,在求和过程中检查每个组。
          • 首先检查该组的大小为 4,如果没有则抛出异常。
          • 在迭代组字符时,如果遇到非数字,则抛出异常。
          • 否则,继续计算当前组的总和,如下所示:
            • 如果字符是数字,则减去 0 以将其转换为 int
              并添加到当前 sums 数组元素中。
          • 完成后,将该组总和添加到所有数字的totalSum
        • 如果totalSum 可以被4 整除,并且第一组比最后一组少一个,则它是一张有效卡。否则,抛出异常。

        替代错误处理修改

        如果不需要异常,而只是通过或失败指示,则进行以下更改。

        • void返回类型更改为boolean
        • 如果抛出异常,直接返回false
        • 如果所有测试都通过,那么最后一条语句应该返回true
        public static void validate(String cardNumber) throws BadCreditCardException {
            int [] groupSums = new int[4];
            int totalSum = 0;
        
            String [] groups = cardNumber.split("-");
        
            if (groups.length != 4) {
                throw new BadCreditCardException("Insufficient or too may dashes");
            }
            for (int i = 0; i < groupSums.length; i++) {
                if (groups[i].length() != 4) {
                     throw new BadCreditCardException("Non group of 4 digits");
                }
                for(int digit : groups[i].toCharArray()) {
                    if (!Character.isDigit(digit)) {
                        throw new BadCreditCardException("Non digit found.");
                    }
                    groupSums[i]+= digit -'0';
                }
                totalSum += groupSums[i];
            }
            if (groupSums[0]+1 != groupSums[3] || totalSum % 4 != 0) {
                throw new BadCreditCardException("Invalid credit card checksum");
            }
        }
        

        【讨论】:

          【解决方案5】:

          信用卡及其部件的单独类

          1. 添加一个管理信用卡部分的 Part 类
          2. 添加一个管理这些部分的 CreditCard 类
          3. 每个部分都有效
          4. 除了单独验证每个药水之外,还要验证其他检查
          5. 根据调用次数的不同,valid&sumDigits方法会被调用,validation/sum可以添加到各自的方法或者构造函数中。
          import java.util.Arrays;
          
          public class CreditCard {
          
              private final String input;
              private final Part[] parts;
              private final boolean valid;
          
              CreditCard(String card) {
                  this.input = card;
                  if (card == null || card.length() != 19) {
                      valid = false;
                      parts = null;
                  } else {
                      parts = Arrays.stream(card.split("-")).map(Part::new).toArray(Part[]::new);
                      final int totalSum = Arrays.stream(parts).mapToInt(Part::sumDigits).sum();
                      valid = totalSum % 4 == 0 && parts.length == 4
                          && parts[0].sumOfDigits + 1 == parts[3].sumOfDigits
                          && Arrays.stream(parts).allMatch(Part::isValid);
                  }
              }
          
              static class Part {
                  final int num;
                  final boolean valid;
                  final int sumOfDigits;
          
                  Part(String part) {
                      int localNum = 0;
                      try {
                          localNum = Integer.parseInt(part);
                      } catch (Throwable ignored) {
                      }
                      this.num = localNum;
                      valid = part.length() == 4 && part.equals(String.format("%04d", num));
                      if (valid) {
                          sumOfDigits = part.chars().map(Character::getNumericValue).sum();
                      } else {
                          sumOfDigits = -1;
                      }
                  }
          
                  boolean isValid() {
                      return valid;
                  }
          
                  int sumDigits() {
                      return sumOfDigits;
                  }
              }
          
              public static void main(String[] args) {
                  String[] creditCards  = {
                      "1000-0000-0001-0002",
                      "0000-0000-0000-0000",
                      "10000-0000-0001-0002",
                      "10000000-0001-0002",
                      "1a00-0000-0001-0002",
                      "1234-4826-6535-1235",
                  };
                  Arrays.stream(creditCards).map(CreditCard::new)
                      .forEach(c -> System.out.println(c.input + " is " + c.valid));
              }
          
          }
          
          

          【讨论】:

            【解决方案6】:

            除了第二个 for 循环和你的 if 条件外,一切都很好。 用以下更改替换您的代码,它应该可以正常工作:

            int firstfourdigits = 0, lastfourdigits = 0;
            
            for(int i=0; i<4; i++)
                firstfourdigits = firstfourdigits + Character.getNumericValue(ccNumber.charAt(i));
            
            for (int m = ccNumber.length()-1; m>ccNumber.length()-5; m--)
                lastfourdigits = lastfourdigits + Character.getNumericValue(ccNumber.charAt(m));
            
            if(firstfourdigits != lastfourdigits - 1){
                valid = false;
                errorCode = 5;
                return;
            }
            

            您根本不需要提取数字。

            【讨论】:

              【解决方案7】:
              public boolean ccnCheck(String ccn){
                  String iccn = ccn.replaceAll("-","");
                  int length = iccn.length();
                  
                  int fsum = 0;
                  int lsum = 0;
                  int allsum = 0;
                  for( int i = 0; i < length; i++){
                      int val = Character.getNumericValue(iccn.charAt(m))
                      if( i < 4)
                          fsum += val;
                      if( i >= length-4)
                          lsum += val;
                      allsum += val;
                  }
                  
                  if( (allsum % 4) != 0)
                      return false;
                  
                  if( fsum != lsum-1 )
                      return false;
                  
                  return true;
              }
              

              【讨论】:

                【解决方案8】:

                在您的规则五检查中,您使用的是 ccNumber 而不是您的数字字符串。

                例如,不应该

                Character.getNumericValue(ccNumber.charAt(i));
                

                改为:

                Character.getNumericValue(digits.charAt(i));
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-02-13
                  • 2012-08-12
                  • 2013-10-09
                  • 2014-07-25
                  • 1970-01-01
                  相关资源
                  最近更新 更多