1. 概述

摩尔斯电码通过点和划的组合来表示字母、数字和标点符号。由塞缪尔·摩尔斯和阿尔弗雷德·维尔在1830年代早期为电报通信开发。

本教程将实现英文到摩尔斯电码的转换方法,以及反向转换方法。

2. 编写摩尔斯电码

2.1 摩尔斯电码基础

摩尔斯电码中,每个字符由短信号(点)和长信号(划)的唯一组合表示。我们使用 . 表示点,- 表示划。但仅用这两个字符无法完整表示句子。

摩尔斯电码通信中,字符间的短暂停顿和单词间的较长停顿至关重要。我们采用以下约定:

  • 字符间用空格分隔
  • 单词间用 / 表示(前后需加空格)

2.2 英文与摩尔斯电码的双向映射

为实现双向转换,我们需要建立英文与摩尔斯电码的双向映射关系。使用 Apache Commons Collections 的 BidiMap 数据结构,它支持通过键或值访问。若只需单向转换,直接使用 Map 即可。

首先在 pom.xml 中添加依赖:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-collections4</artifactId>
    <version>4.4</version>
</dependency>

创建映射类并初始化:

public class MorseTranslator {
    
    private static final BidiMap<String, String> morseAlphabet = new DualHashBidiMap<>();
    
    static {
        morseAlphabet.put("A", ".-");
        morseAlphabet.put("B", "-...");
        morseAlphabet.put("C", "-.-.");
        morseAlphabet.put("D", "-..");
        morseAlphabet.put("E", ".");
        morseAlphabet.put("F", "..-.");
        morseAlphabet.put("G", "--.");
        morseAlphabet.put("H", "....");
        morseAlphabet.put("I", "..");
        // 等等...
        morseAlphabet.put(" ", "/");
    }
}

⚠️ 注意:

  • 映射表只包含大写字母(转换时统一转为大写)
  • 空格字符已特殊处理
  • 重音字符(如 à, å)可能对应相同摩尔斯码,需特殊处理

3. 将英文翻译为摩尔斯电码

3.1 核心算法

转换步骤:统一转为大写 → 逐字符翻译 → 用空格拼接

static String englishToMorse(String english) {
    String upperCaseEnglish = english.toUpperCase();
    String[] morse = new String[upperCaseEnglish.length()];
    for (int index = 0; index < upperCaseEnglish.length(); index++) {
        String morseCharacter = morseAlphabet.get(String.valueOf(upperCaseEnglish.charAt(index)));
        morse[index] = morseCharacter;
    }
    return String.join(" ", morse);
}

使用参数化测试验证大小写不敏感:

@ParameterizedTest
@ValueSource(strings = {"MORSE CODE!", "morse code!", "mOrSe cOdE!"})
void givenAValidEnglishWordWhateverTheCapitalization_whenEnglishToMorse_thenTranslatedToMorse(String english) {
    assertEquals("-- --- .-. ... . / -.-. --- -.. . -.-.-----.", MorseTranslator.englishToMorse(english));
}

3.2 边界情况处理

需拒绝包含非法字符的输入,抛出 IllegalArgumentException

static String englishToMorse(String english) {
    if (english == null) {
        return null;
    }
    String upperCaseEnglish = english.toUpperCase();
    String[] morse = new String[upperCaseEnglish.length()];
    for (int index = 0; index < upperCaseEnglish.length(); index++) {
        String morseCharacter = morseAlphabet.get(String.valueOf(upperCaseEnglish.charAt(index)));
        if (morseCharacter == null) {
            throw new IllegalArgumentException("Character " + upperCaseEnglish.charAt(index) + " can't be translated to morse");
        }
        morse[index] = morseCharacter;
    }
    return String.join(" ", morse);
}

测试非法字符场景:

@Test
void givenAnEnglishWordWithAnIllegalCharacter_whenEnglishToMorse_thenThrows() {
    String english = "~This sentence starts with an illegal character";
    assertThrows(IllegalArgumentException.class, () -> MorseTranslator.englishToMorse(english));
}

4. 将摩尔斯电码翻译为英文

4.1 核心算法

转换步骤:按空格分割摩尔斯字符 → 逐个反向查询 → 拼接结果

static String morseToEnglish(String morse) {
    String[] morseUnitCharacters = morse.split(" ");
    StringBuilder stringBuilder = new StringBuilder();
    for (int index = 0; index < morseUnitCharacters.length; index ++) {
        String englishCharacter = morseAlphabet.getKey(morseUnitCharacters[index]);
        stringBuilder.append(englishCharacter);
    }
    return stringBuilder.toString();
}

验证转换结果:

@Test
void givenAValidMorseWord_whenMorseToEnglish_thenTranslatedToUpperCaseEnglish() {
    assertEquals("MORSE CODE!", MorseTranslator.morseToEnglish("-- --- .-. ... . / -.-. --- -.. . -.-.-----."));
}

✅ 输出始终为大写字母

4.2 边界情况处理

需处理三种异常情况

  1. null 输入
  2. 空字符串(split() 方法特殊行为)
  3. 非法摩尔斯字符

最终实现:

static String morseToEnglish(String morse) {
    if (morse == null) {
        return null;
    }
    if (morse.isEmpty()) {
        return "";
    }
    String[] morseUnitCharacters = morse.split(" ");
    StringBuilder stringBuilder = new StringBuilder();
    for (int index = 0; index < morseUnitCharacters.length; index ++) {
        String englishCharacter = morseAlphabet.getKey(morseUnitCharacters[index]);
        if (englishCharacter == null) {
            throw new IllegalArgumentException("Character " + morseUnitCharacters[index] + " is not a valid morse character");
        }
        stringBuilder.append(englishCharacter);
    }
    return stringBuilder.toString();
}

测试非法摩尔斯字符:

@Test
void givenAMorseWordWithAnIllegalCharacter_whenMorseToEnglish_thenThrows() {
    assertThrows(IllegalArgumentException.class, () -> MorseTranslator.morseToEnglish(".!!!!!!!"));
}

5. 总结

本文实现了摩尔斯电码与英文的双向转换器。核心要点:

  • 使用 BidiMap 维护双向映射
  • ✅ 正确处理字符/单词分隔符
  • ❌ 严格校验非法输入
  • 💡 可扩展为通用语言转换框架

完整代码见 GitHub 仓库


原始标题:Simple Morse Code Translation in Java