1. 概述

有时我们需要处理以文本形式表达的电话号码,例如通过语音转文本接口获取的电话号码。本文将介绍一种算法,用于处理表示数字序列的单词序列,并将其转换为数字字符串。

2. 问题场景详解

输入的格式值得深入分析。我们可能会收到类似 "five six eight" 的电话号码单词形式。但实际口语中常包含倍数词,如 "double two"。因此算法需要处理以下转换:

输入: "triple five two three six eight"
预期输出: "5552368"

3. 使用switch语句实现算法

核心思路是将输入拆分为单词数组,逐个处理并构建输出结果。通过switch语句对单词分类处理。

3.1. 字符串拆分为单词数组

首先使用String.split()方法按空格分割输入字符串:

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

然后使用for-each循环遍历数组:

for (String word : words) {
    // 处理逻辑
}

3.2. 处理倍数词

在循环中检查当前单词是否为倍数词:

Integer multiplier = getWordAsMultiplier(word);
if (multiplier != null) {
    if (currentMultiplier != null) {
        throw new IllegalArgumentException("不能出现连续的倍数词,错误位置: " + word);
    }
    currentMultiplier = multiplier;
}

通过getWordAsMultiplier()方法映射倍数词:

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

⚠️ 注意:连续倍数词(如"double triple")会抛出异常。

3.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("无效单词: " + word);
    }
}

关键点:所有单词必须是数字词或倍数词,否则抛出异常。

3.4. 组装数字结果

使用StringBuilder构建结果,根据倍数词重复数字:

if (multiplier != null) {
    // 倍数词处理逻辑
} else {
   output.append(getWordAsDigit(word)
     .repeat(currentMultiplier != null ? currentMultiplier : 1));
   currentMultiplier = null;
}

技巧String.repeat()方法轻松实现数字重复,默认重复1次。

3.5. 测试验证

验证三种场景:正确号码、无效单词、连续倍数词:

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

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

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

4. 使用Map替代switch语句

switch语句虽然有效但略显冗长,我们可以用Map优化实现。

4.1. 初始化数字和倍数映射

使用Map.of()创建不可变映射:

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

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

🛡️ 安全设计:使用不可变Map防止运行时修改导致错误。

4.2. 检查倍数词

直接通过Map获取倍数值:

Integer multiplier = multipliers.get(word);

4.3. 检查数字词

获取数字后验证有效性:

String digit = digits.get(word);

if (digit == null) {
    throw new IllegalArgumentException("无效单词: " + word);
}

4.4. 测试验证

Map版本通过相同测试用例:

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

5. 总结

本文实现了两种电话号码单词转换方案:

  1. switch方案:逻辑直观但代码冗长
  2. Map方案:简洁高效,推荐生产使用

两种方案均能正确处理倍数词和数字词组合,并具备完善的错误处理机制。完整代码可在GitHub获取。


原始标题:Convert a Phone Number in Words to Number with Java