【问题标题】:Empty string added to string array when splitting for numbers [duplicate]拆分数字时将空字符串添加到字符串数组[重复]
【发布时间】:2021-03-10 20:34:33
【问题描述】:

我目前正在尝试使用 codebat 为大学学习 Java。我的目标是获取任何 ASCII 字符的字符串,从字符串中拆分所有数字,然后将所有数字的总和作为 int 返回。

例如:foo("abc123xyz") 应返回 123,foo("12cd43ad") 应返回 55

这是我的代码:

public int sumNumbers(String str) {
  int sum = 0;
  
  String[] numArr = str.split("\\D+"); //This is my attempted regex
  for (String num: numArr) {
    sum += Integer.parseInt(num);
  }
  
  return sum;
}

当我运行 sumNumbers("abc123xyz")sumNumbers("aa11b33") 时,我收到此错误:

NumberFormatException: For input string: ""

为什么我的 numArr 中有一个空字符串,解决此问题的正确正则表达式是什么?

【问题讨论】:

  • 因为你用非数字作为分隔符进行拆分,而这个分隔符出现在字符串的开头。文档中也描述了此行为。简单修复:包装在 if 语句中:if (!num.isEmpty()) { ... }

标签: java arrays regex split


【解决方案1】:

Matcher 更适用于这个目的然后拆分:

int sum = 0;
Pattern p = Pattern.compile("\\d+");
Matcher m = p.matcher(str);
while(m.find()) {
    sum+=Integer.parseInt(m.group());
}
return sum;

【讨论】:

    【解决方案2】:

    可能需要通过非数字序列过滤掉split("\\D+")之后的空值。

    此外,流 API 也可用于计算总和:

    public static int sumNumbers(String str) {
        return Arrays.stream(str.split("\\D+"))   // Stream<String>
                     .filter(s -> !s.isEmpty())   // remove empty strings 
                     .mapToInt(Integer::parseInt) // get IntStream (stream of primitive int)
                     .sum();
    }
    

    测试:

    System.out.println(sumNumbers("abc123z-3yx"));   // 123 + 3
    System.out.println(sumNumbers("12abc34z-6yx"));  // 12 + 34 + 6
    

    输出:

    126
    52
    

    同样,可以使用匹配数字序列"-?\\d+" 的模式(包括可选的-? 来处理负值):

    public static int sumNumbers(String str) {
        Pattern p = Pattern.compile("-?\\d+");
        return p.matcher(str)
                .results()                   // Stream<MatchResult> since Java 9
                .map(MatchResult::group)     // get the matched sequence as string
                .mapToInt(Integer::parseInt) // get primitive int
                .sum();
    }
    

    相同测试数据的结果:(123 - 3) 和 (12 + 34 - 6)

    120
    40
    

    【讨论】:

      【解决方案3】:

      检查String#split的文档中的以下几行:

      当此字符串的开头存在正宽度匹配时 然后在开头包含一个空的前导子字符串 结果数组。开头的零宽度匹配但从不 产生这样的空前导子字符串。

      您可以通过打印结果数组来确认它。空字符串无法解析为int。一种解决方法是忽略无法解析为int 的字符串。

      public class Main {
          public static void main(String[] args) {
              // Tests
              System.out.println(sumNumbers("abc123xyz"));
              System.out.println(sumNumbers("12cd43ad"));
          }
      
          public static int sumNumbers(String str) {
              int sum = 0;
      
              String[] numArr = str.split("\\D+");
              //System.out.println(Arrays.toString(numArr));
              for (String num : numArr) {
                  try {
                      sum += Integer.parseInt(num);
                  } catch (NumberFormatException e) {
                      // Ignore the strings which can not be parsed into int
                  }
              }
      
              return sum;
          }
      }
      

      输出:

      123
      55
      

      【讨论】:

        【解决方案4】:

        您正在拆分非数字,除非第一个字符是数字,否则您将得到一个空白字符串,因为根据 java doc,这是正确的行为 https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#split-java.lang.String-int-

        您的函数适用于以数字为首字符的字符串。

        【讨论】:

          猜你喜欢
          • 2013-08-19
          • 2012-12-15
          • 1970-01-01
          • 1970-01-01
          • 2016-03-22
          • 1970-01-01
          • 2019-08-30
          • 2014-05-16
          • 1970-01-01
          相关资源
          最近更新 更多