-2

I am currently trying to brush up on Java for university using codebat. My goal is to take a string of any ASCII characters, split all of the numbers from the string, then return the sum of all of the numbers as an int.

For example: foo("abc123xyz") should return 123 and foo("12cd43ad") should return 55

Here is my code:

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

When I run sumNumbers("abc123xyz") or sumNumbers("aa11b33"), I get this error:

NumberFormatException: For input string: ""

Why is there an empty string in my numArr, and what is the proper regex to solve this issue?

1
  • Because you split with non-digits as separator, and this separator occurs at the beginning of the string. This behavior is also described in the documentation. Simple fix: wrap in an if statement: if (!num.isEmpty()) { ... }. Commented Nov 28, 2020 at 9:28

4 Answers 4

3

Matcher is more applicable for this purpose then split:

int sum = 0;
Pattern p = Pattern.compile("\\d+");
Matcher m = p.matcher(str);
while(m.find()) {
    sum+=Integer.parseInt(m.group());
}
return sum;
Sign up to request clarification or add additional context in comments.

Comments

1

Check the following lines from the documentation of String#split:

When there is a positive-width match at the beginning of this string then an empty leading substring is included at the beginning of the resulting array. A zero-width match at the beginning however never produces such empty leading substring.

You can confirm it by printing the resulting array. An empty string can not be parsed into an int. A workaround is to ignore the strings which can not be parsed into an 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;
    }
}

Output:

123
55

Comments

0

You are splitting on the non-digits, unless the first character is a digit you're going to get a blank string, because it's the correct behavior according to the java doc https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#split-java.lang.String-int-

Your function works fine on strings with digits as first characters.

Comments

0

It may be needed to filter out the empty values after the split("\\D+") by non-digit sequences.

Also, stream API may be used to calculate the sum:

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

Test:

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

Output:

126
52

Similarly, a pattern to match digit sequences "-?\\d+" (including optional -? to handle negative values) may be used:

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

Results for the same test data: (123 - 3) and (12 + 34 - 6)

120
40

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.