Course – LS – All

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

>> CHECK OUT THE COURSE

1. Overview

We may wish to process a telephone number expressed as text. Perhaps we have received a telephone number via a speech-to-text interface.

In this tutorial, we’ll look at an algorithm for processing a sequence of words expressing a numeric sequence and converting it to a string of digits.

2. Introduction to Problem Statement

Let’s look a little deeper at the format of the input. We’ll be given a phone number in words, such as “five six eight”. However, it’s common for spoken numbers to include multipliers, such as “double two”.

So, we expect our algorithm to convert:

Input: "triple five two three six eight"
Expected Output: "5552368"

3. Implementing the Algorithm with switch Statements

The algorithm splits the input into words and processes each to build the output. We can classify the words using switch statements.

3.1. Split String into Words Array

First, we need to use the String.split() method to split the phoneNumberInWords string into an array of words using a space as the delimiter:

String[] words = phoneNumberInWords.split(" ");

We can then use a for-each loop to iterate over the words array:

for (String word : words) {
    // statements
}

3.2. Handle Multipliers

In each iteration of the for-each loop, we will check if the current word represents a multiplier:

Integer multiplier = getWordAsMultiplier(word);
if (multiplier != null) {
    if (currentMultiplier != null) {
        throw new IllegalArgumentException("Cannot have consecutive multipliers, at: " + word);
    }
    currentMultiplier = multiplier;
}

We invoke the getWordAsMultiplier() method by passing the current word as an argument. This method maps the current word to its corresponding numerical representation and returns it.

If the returned value is not null, indicating the current word is indeed a multiplier, we check if there is already a multiplier set. If there is, we throw an IllegalArgumentException because consecutive multipliers are not allowed. Otherwise, we set the current multiplier.

To identify whether a word is a multiplier, we use a switch statement inside getWordAsMultiplier():

public static Integer getWordAsMultiplier(String word) {
    switch (word) {
        case "double":
            return 2;
        case "triple":
            return 3;
         case "quadruple":
            return 4;
         default:
            return null;
    }
}

It’s not an error if the current word isn’t a multiplier, so this method returns null in that instance.

3.3. Handle Non-multiplier Word

If the current word isn’t a multiplier word, we call the getWordAsDigit() method:

public static String getWordAsDigit(String word) {
    switch (word) {
        case "zero":
            return "0";
        case "one":
            return "1";
        ...
        ...
        ...
        case "nine":
            return "9";
        default:
            throw new IllegalArgumentException("Invalid word: " + word);
    }
}

This will be called in the else statement of the if where we check for a multiplier word. As a word must be either a multiplier or a digit, this function should throw an exception if we call it with a non-digit number. Here, we’ve used IllegalArgumentException.

3.4. Assembling Digits

Let’s use the getWordAsDigit() method. In the multiplier processing code, we’ve captured any duplication of digits, so now we’re going to find the current digit and add it to the output as many times as necessary.

We’ll use a StringBuilder object called output to store our results.

We use the append() method to assemble the output. However, the String.repeat() method tracks the multiplier. We repeat the obtained digit representation of the current word based on the current multiplier:

if (multiplier != null) {
    // multiplier processing
} else {
   output.append(getWordAsDigit(word)
     .repeat(currentMultiplier != null ? currentMultiplier : 1));
   currentMultiplier = null;
}

We use StringBuilder.append() to add the next set of digits to the output.

If the current multiplier is not null, we use it to provide copies of the next digit, using String.repeat(), defaulting to a repeat of 1 when there is no multiplier.

At the end of the loop, the output object contains our phone number:

return output.toString();

3.5. Test Solution

Let’s see what happens when a correct phone number, invalid word, or consecutive multipliers are given:

assertEquals("5248888", 
  UseSwitchToConvertPhoneNumberInWordToNumber 
    .convertPhoneNumberInWordToNumber("five two four quadruple eight"));

assertThrows(IllegalArgumentException.class, () -> {
    UseSwitchToConvertPhoneNumberInWordToNumber
      .convertPhoneNumberInWordToNumber("five eight invalid two four null eight");
});

assertThrows(IllegalArgumentException.class, () -> {
    UseSwitchToConvertPhoneNumberInWordToNumber
      .convertPhoneNumberInWordToNumber("five eight three double triple");
});

4. Using Map Instead of switch

Our algorithm works well, but switch statements can be a little long-winded. We can replace them with Map objects.

The Map.of() method creates an immutable Map with the provided key-value pairs. In this section, we’ll use the Map.of() method to map multipliers (“double” to 2) and digits (“two” to “2”).

4.1. Map Digits and Multipliers

Let’s initialize the Map to create mappings for individual digits:

private static Map<String, Integer> multipliers 
  = Map.of("double", 2, "triple", 3, "quadruple", 4);

Next, we initialize another Map to map multipliers:

private static Map<String, String> digits 
  = Map.of("zero", "1", "one", "1", "two", "2", "three", "3",
    "four", "4", "five", "5", "six", "6", "seven", "7", "eight", "8", "nine", "9");

We initialize them as immutable because the algorithm would stop working if the Map could change at runtime.

4.2. Check Multiplier

As before, inside the loop, we want to find a multiplier or null. We can use the get() method on multipliers:

Integer multiplier = multipliers.get(word);

4.3. Check Digits

To replicate the exception, when a word is not a digit, we need an additional if statement after the get() on digits:

String digit = digits.get(word);

if (digit == null) {
    throw new IllegalArgumentException("Invalid word: " + word);
}

4.4. Test Solution

We can run the same tests on this solution, such as:

assertEquals("5248888",
  UseHashMapToConvertPhoneNumberInWordsToNumber
    .convertPhoneNumberInWordToNumber("five two four quadruple eight"));

5. Conclusion

In this article, we looked at an algorithm for processing telephone numbers.

We implemented the basic algorithm using switch statements. Then, we optimized the implementation using Java Map.

As always, the example code is 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.