Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE

1. Overview

Sometimes we need to find numeric digits or full numbers in strings. We can do this with both regular expressions or certain library functions.

In this article, we’ll use regular expressions to find and extract numbers in strings. We’ll also cover some ways to count digits.

2. Counting Numeric Digits

Let’s start by counting the digits found within a string.

2.1. Using Regular Expressions

We can use Java Regular Expressions to count the number of matches for a digit.

In regular expressions, \d matches “any single digit”. Let’s use this expression to count digits in a string:

int countDigits(String stringToSearch) {
    Pattern digitRegex = Pattern.compile("\\d");
    Matcher countEmailMatcher = digitRegex.matcher(stringToSearch);

    int count = 0;
    while (countEmailMatcher.find()) {
        count++;
    }

    return count;
}

Once we have defined a Matcher for the regex, we can use it in a loop to find and count all the matches. Let’s test it:

int count = countDigits("64x6xxxxx453xxxxx9xx038x68xxxxxx95786xxx7986");

assertThat(count, equalTo(21));

2.2. Using the Google Guava CharMatcher

To use Guava, we first need to add the Maven dependency:

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>31.0.1-jre</version>
</dependency>

Guava provides the CharMatcher.inRange​ method for counting digits:

int count = CharMatcher.inRange('0', '9')
  .countIn("64x6xxxxx453xxxxx9xx038x68xxxxxx95786xxx7986");

assertThat(count, equalTo(21));

3. Finding Numbers

Counting numbers requires patterns that capture all the digits of a valid numeric expression.

3.1. Finding Integers

To construct an expression to recognize integers, we must consider that they can be positive or negative and consist of a sequence of one or more digits. We also note that negative integers are preceded by a minus sign.

Thus, we can find integers by extending our regex to “-?\d+“. This pattern means “an optional minus sign, followed by one or more digits”.

Let’s create an example method that uses this regex to find integers in a string:

List<String> findIntegers(String stringToSearch) {
    Pattern integerPattern = Pattern.compile("-?\\d+");
    Matcher matcher = integerPattern.matcher(stringToSearch);

    List<String> integerList = new ArrayList<>();
    while (matcher.find()) {
        integerList.add(matcher.group());
    }

    return integerList;
}

Once we have created a Matcher on the regex, we use it in a loop to find all the integers in a string. We call group on each match to get all the integers.

Let’s test findIntegers:

List<String> integersFound = 
  findIntegers("646xxxx4-53xxx34xxxxxxxxx-35x45x9xx3868xxxxxx-95786xxx79-86");

assertThat(integersFound)
  .containsExactly("646", "4", "-53", "34", "-35", "45", "9", "3868", "-95786", "79", "-86");

3.2. Finding Decimal Numbers

To create a regex that finds decimal numbers, we need to consider the pattern of characters used when writing them.

If a decimal number is negative, it starts with a minus sign. This is followed by one or more digits and an optional fractional part. This fractional part starts with a decimal point, with another sequence of one or more digits after that.

We can define this using the regular expression “-?\d+(\.\d+)?“:

List<String> findDecimalNums(String stringToSearch) {
    Pattern decimalNumPattern = Pattern.compile("-?\\d+(\\.\\d+)?");
    Matcher matcher = decimalNumPattern.matcher(stringToSearch);

    List<String> decimalNumList = new ArrayList<>();
    while (matcher.find()) {
        decimalNumList.add(matcher.group());
    }

    return decimalNumList;
}

Now we’ll test findDecimalNums:

List<String> decimalNumsFound = 
  findDecimalNums("x7854.455xxxxxxxxxxxx-3x-553.00x53xxxxxxxxxxxxx3456xxxxxxxx3567.4xxxxx");

assertThat(decimalNumsFound)
  .containsExactly("7854.455", "-3", "-553.00", "53", "3456", "3567.4");

4. Converting the Strings Found into Numeric Values

We may also wish to convert the found numbers into their Java types.

Let’s convert our integer numbers into Long using Stream mapping:

LongStream integerValuesFound = findIntegers("x7854x455xxxxxxxxxxxx-3xxxxxx34x56")
  .stream()
  .mapToLong(Long::valueOf);
        
assertThat(integerValuesFound)
  .containsExactly(7854L, 455L, -3L, 34L, 56L);

Next, we’ll convert decimal numbers to Double in the same way:

DoubleStream decimalNumValuesFound = findDecimalNums("x7854.455xxxxxxxxxxxx-3xxxxxx34.56")
  .stream()
  .mapToDouble(Double::valueOf);

assertThat(decimalNumValuesFound)
  .containsExactly(7854.455, -3.0, 34.56);

5. Finding Other Types of Numbers

Numbers can be expressed in other formats, which we can detect by adjusting our regular expressions.

5.1. Scientific Notation

Let’s find some numbers formatted using scientific notation:

String strToSearch = "xx1.25E-3xxx2e109xxx-70.96E+105xxxx-8.7312E-102xx919.3822e+31xxx";

Matcher matcher = Pattern.compile("-?\\d+(\\.\\d+)?[eE][+-]?\\d+")
  .matcher(strToSearch);

// loop over the matcher

assertThat(sciNotationNums)
  .containsExactly("1.25E-3", "2e109", "-70.96E+105", "-8.7312E-102", "919.3822e+31");

5.2. Hexadecimal

Now we’ll find hexadecimal numbers in a string:

String strToSearch = "xaF851Bxxx-3f6Cxx-2Ad9eExx70ae19xxx";

Matcher matcher = Pattern.compile("-?[0-9a-fA-F]+")
  .matcher(strToSearch);

// loop over the matcher

assertThat(hexNums)
  .containsExactly("aF851B", "-3f6C", "-2Ad9eE", "70ae19");

6. Conclusion

In this article, we first discussed how to count digits in a string using regular expressions and the CharMatcher class from Google Guava.

Then, we explored using regular expressions to find integers and decimal numbers.

Finally, we covered finding numbers in other formats such as scientific notation and hexadecimal.

As always, the source code for this tutorial can be found over on GitHub.

Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

>> CHECK OUT THE COURSE
res – REST with Spring (eBook) (everywhere)
Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.