Java中将电话号码转换为数字

在本教程中,我们将了解一种用于处理表示数字序列的单词序列并将其转换为数字字符串的算法。

让我们更深入地了解一下输入的格式。我们将收到一个文字电话号码,例如“五六八”。然而,口头数字通常包含乘数,例如“双倍二”。

因此,我们期望我们的算法能够转换:

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

使用switch语句实现算法
该算法将输入拆分为单词并处理每个单词以构建输出。我们可以使用switch语句对单词进行分类。

1.将字符串拆分为单词数组
首先,我们需要使用字符串。split()方法使用空格作为分隔符将phoneNumberInWords字符串拆分为单词数组:

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

然后我们可以使用for-each循环来迭代单词数组:

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

2.处理乘数
在for-each循环的每次迭代中,我们将检查当前单词是否表示乘数:

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

我们通过将当前单词作为参数传递来调用getWordAsMultiplier()方法。此方法将当前单词映射到其相应的数字表示形式并返回它。

如果返回值不为null,表明当前单词确实是一个乘数,我们检查是否已经有一个乘数集。如果存在,我们会抛出IllegalArgumentException,因为不允许使用连续乘数。否则,我们设置当前的乘数。

为了识别一个单词是否是乘数,我们在getWordAsMultiplier()中使用switch语句:

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

如果当前单词不是乘数,则不是错误,因此此方法在该实例中返回null 。

3.处理非乘数词
如果当前单词不是乘数单词,我们调用getWordAsDigit()方法:

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

这将在if的else语句 中调用 ,我们在其中检查乘数词。由于单词必须是乘数或数字,因此如果我们使用非数字来调用此函数,则应抛出异常。在这里,我们使用了IllegalArgumentException。

4.组合数字
让我们使用 getWordAsDigit() 方法。在乘法器处理代码中,我们已经捕获了任何重复的数字,因此现在我们将找到当前数字并将其添加到输出中(根据需要多次)。

我们将使用一个 名为 “output”的StringBuilder对象来存储我们的结果。

我们使用append()方法来组装输出。但是,String.repeat()方法跟踪乘数。我们根据当前乘数重复获得的当前单词的数字表示:

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

我们使用StringBuilder.append()将下一组数字添加到输出中。

如果当前乘数不为null,我们用它来提供下一个数字的副本,使用String.repeat(),当没有乘数时默认重复 1。

在循环结束时, 输出对象包含我们的电话号码:

return output.toString();

5.测试方案
让我们看看当给出正确的电话号码、无效的单词或连续的乘数时会发生什么:

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

使用Map代替switch
我们的算法运行良好,但 switch语句可能有点冗长。我们可以用Map对象替换它们 。

Map.of ()方法使用提供的键值对创建一个不可变的Map 。在本节中,我们将使用Map.of()方法来映射乘数(“double”到 2)和数字(“two”到“2”)。

1.map数字和乘数
让我们初始化Map来为各个数字创建映射:

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

接下来,我们初始化另一个Map来映射乘数:

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");

我们将它们初始化为不可变的,因为如果映射在运行时发生变化,算法将停止工作。

2.检查乘数
和以前一样,在循环内部,我们想要找到一个乘数或空值。我们可以在乘数上使用get()方法:

Integer multiplier = multipliers.get(word);

3.校验位
为了复制异常,当单词不是数字时,我们需要 在数字上的 get()之后添加一个if语句 :

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

4.测试方案
我们可以对此解决方案运行相同的测试,例如:

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