首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >转换Morse码

转换Morse码
EN

Code Review用户
提问于 2016-07-17 20:26:57
回答 2查看 7.3K关注 0票数 10

挑战

编写一个程序,读取包含Morse代码的文件并输出转换。

Specifications

  1. 第一个参数是文件的路径。
  2. 该文件包含多行。
  3. 每一行都是一串莫尔斯码。
    • 每个字母都用空格隔开。
    • 每个单词由两个空格隔开。

约束

  1. 输入文件被正确格式化。
  2. 莫尔斯电码字符串是字母数字。

样本输入

.- .。。。-.-...…….,--

样本输出

AV2WHIECX 45 BH3

来源

我的解决方案:

代码语言:javascript
复制
import java.io.File;
import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;

public class Solution {
    private static final Map<String, Character> morseAlphabet = new HashMap<>();

    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(".---", 'J');
        morseAlphabet.put("-.-", 'K');
        morseAlphabet.put(".-..", 'L');
        morseAlphabet.put("--", 'M');
        morseAlphabet.put("-.", 'N');
        morseAlphabet.put("---", 'O');
        morseAlphabet.put(".--.", 'P');
        morseAlphabet.put("--.-", 'Q');
        morseAlphabet.put(".-.", 'R');
        morseAlphabet.put("...", 'S');
        morseAlphabet.put("-", 'T');
        morseAlphabet.put("..-", 'U');
        morseAlphabet.put("...-", 'V');
        morseAlphabet.put(".--", 'W');
        morseAlphabet.put("-..-", 'X');
        morseAlphabet.put("-.--", 'Y');
        morseAlphabet.put("--..", 'Z');
        morseAlphabet.put("-----", '0');
        morseAlphabet.put(".----", '1');
        morseAlphabet.put("..---", '2');
        morseAlphabet.put("...--", '3');
        morseAlphabet.put("....-", '4');
        morseAlphabet.put(".....", '5');
        morseAlphabet.put("-....", '6');
        morseAlphabet.put("--...", '7');
        morseAlphabet.put("---..", '8');
        morseAlphabet.put("----.", '9');
    }

    public static void main(String[] args) {
        if (args.length != 1) {
            System.err.println(args.length > 1 ? "Excessive arguments, only the first will be considered" : "No arguments provided.");
            System.exit(1);
        }

        try (Scanner fileScanner = new Scanner(new File(args[0]))) {
            while (fileScanner.hasNextLine()) {
                System.out.println(decode(fileScanner.nextLine()));
            }
        } catch (FileNotFoundException fnfe) {
            fnfe.printStackTrace();
        }
    }

    private static String decode(String morse) {
        StringBuilder decoded = new StringBuilder();

        String[] words = morse.split("\\s{2}");
        for (String word : words) {
            decoded.append(' ');
            String[] letters = word.split("\\s");
            for (String letter : letters) {
                decoded.append(morseAlphabet.get(letter));
            }
        }

        return decoded.substring(1);
    }
}

测试:

代码语言:javascript
复制
import org.junit.Test;
import static org.junit.Assert.assertEquals;

public class TestMorseConversion {
    @Test
    public void testCodeReviewMorse() {
        assertEquals(Morse.decode("-.-. --- -.. .  .-. . ...- .. . .--"), "CODE REVIEW");
    }

    @Test
    public void test2ndMonitor() {
        assertEquals(Morse.decode("..--- -. -..  -- --- -. .. - --- .-."), "2ND MONITOR");
    }

    @Test
    public void testFromCodeEval() {
        assertEquals(Morse.decode("..-. .-. --- --  -.-. --- -.. . . ...- .- .-.."), "FROM CODEEVAL");
    }
}

注意: Morse类只包含上面使用的映射和decode方法,以方便测试。

EN

回答 2

Code Review用户

回答已采纳

发布于 2016-07-17 21:09:36

有争议..。还有一个窃听器?

像这样的构造是个人偏好所起的作用之一,但要考虑:

if (args.length != 1) { System.err.println(args.length > 1 ? "Excessive arguments, only the first will be considered" : "No arguments provided."); System.exit(1); }

错误处理是通过显式地将错误条件分离出来使之更易读的锅炉板。在检查/重构这一点时,我也发现了一个明显的错误(由于复合退出条件很难识别)。错误在于,如果arg计数大于1,则打印消息“过多的参数,只有第一个参数才会被考虑”,但无论如何,都会终止.太无视后续的args了..。我更希望:

代码语言:javascript
复制
private static final void terminate(String message) {
    System.err.println(message);
    System.exit(1);
}

.....

    if (args.length == 0) {
        terminate("No arguments provided");
    }
    if (args.length > 1) {
        terminate("Too many arguments provided. Expect exactly 1");
    }

当您分离出错误条件时,我发现一个明显的优点是维护它们更简单,特别是在使用版本控制时,因为差异更容易理解。

挑战

编程方面的挑战往往是时间限制的。虽然在大多数情况下,您的代码足够快,但是有一种简单的技术可以显著提高性能--做批量操作(以牺牲内存的使用为代价)。具体来说,最好是将输出“累加”到"StringBuilder“中,然后在最后有一个System.out.println()。您目前拥有的循环中的println将导致系统“刷新”每一行,这通常相当于程序时间的重要部分(超过一半?)。

类似地,在一次“吞咽”中读取整个输入文件通常比扫描仪或其他操作要快。

显然,理论上“巨大”的输入可能是一个问题,但我还没有在挑战中被这样的条件所伤害。

Gulping

我会考虑使用gulp函数来读取整个文件--Java8 java.nio.files包可以在这里提供帮助,我可以选择:

代码语言:javascript
复制
List<String> data = Files.readAllLines(Paths.get(args[0]));

分裂

将空字符串加载到解码例程以输出空格的技巧将允许您使用regex拆分并处理流中的每一行:

代码语言:javascript
复制
private static final Pattern charsplit = Pattern.compile(" ");

然后:

代码语言:javascript
复制
String out = charsplit.splitAsStream(line)
             .map(letter -> morseAlphabet.get(letter))
             .collect(Collectors.joining(""));

然后,可以用换行符将该out附加到输出缓冲区.因此,整个过程看起来有点像(未经测试-参见工作代码的结论):

代码语言:javascript
复制
String output = Files.readAllLines(Paths.get(args[0])).stream()
     .map(line -> charsplit.splitAsStream(line)
                           .map(letter -> morseAlphabet.get(letter)
                           .collect(Collectors.joining("")))
     .collect(Collectors.joining("\n");

System.out.println(output);

我可能会从内部流中得到一个真正的Function<String,String>。我也会让打印成为一个单独的功能..。它不应该是解析/解码的一部分。

结论

我在这里编写了一个工作示例程序:https://ideone.com/hCpUA1

请注意,我最喜欢的代码版本是将各种函数分开,并将Map<String, Character>转换为Map<String, String>。请注意,映射中还包含"Space“值。

此外,文件的读取和转换到List<String>的工作应该在函数(在主方法中)之外,这在ideone.com中是无法完成的。

下面是完整的代码:

代码语言:javascript
复制
import java.util.*;
import java.lang.*;
import java.io.*;
import java.util.stream.*;
import java.util.regex.Pattern;


class Morse
{

    private static final Map<String, String> morseAlphabet = new HashMap<>();

    static {
        morseAlphabet.put("", " ");
        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(".---", "J");
        morseAlphabet.put("-.-", "K");
        morseAlphabet.put(".-..", "L");
        morseAlphabet.put("--", "M");
        morseAlphabet.put("-.", "N");
        morseAlphabet.put("---", "O");
        morseAlphabet.put(".--.", "P");
        morseAlphabet.put("--.-", "Q");
        morseAlphabet.put(".-.", "R");
        morseAlphabet.put("...", "S");
        morseAlphabet.put("-", "T");
        morseAlphabet.put("..-", "U");
        morseAlphabet.put("...-", "V");
        morseAlphabet.put(".--", "W");
        morseAlphabet.put("-..-", "X");
        morseAlphabet.put("-.--", "Y");
        morseAlphabet.put("--..", "Z");
        morseAlphabet.put("-----", "0");
        morseAlphabet.put(".----", "1");
        morseAlphabet.put("..---", "2");
        morseAlphabet.put("...--", "3");
        morseAlphabet.put("....-", "4");
        morseAlphabet.put(".....", "5");
        morseAlphabet.put("-....", "6");
        morseAlphabet.put("--...", "7");
        morseAlphabet.put("---..", "8");
        morseAlphabet.put("----.", "9");
    }


    private static final Pattern charsplit = Pattern.compile(" ");

    private static final String decodeLine(String line) {
        return charsplit.splitAsStream(line)
                   .map(letter -> morseAlphabet.get(letter))
                   .collect(Collectors.joining(""));
    }

    public static final String decode(List<String> data) {
        String output = data.stream()
             .map(Morse::decodeLine)
             .collect(Collectors.joining("\n"));
        return output;
    }

    public static void main (String[] args) throws java.lang.Exception {
        String out = Morse.decode(Arrays.asList(
               "-.-. --- -.. .  .-. . ...- .. . .--",
               "..--- -. -..  -- --- -. .. - --- .-.",
               "..-. .-. --- --  -.-. --- -.. . . ...- .- .-.."));
        System.out.println(out);
    }

}
票数 6
EN

Code Review用户

发布于 2016-07-19 19:06:13

作为一个不变的常量,morseAlphabet映射会更好:

代码语言:javascript
复制
private static final Map<String, String> MORSE_ALPHABET;
static {
    Map<String, String> m = new HashMap<>();
    m.put(".-",     "A");
    m.put("-...",   "B");
    m.put("-.-.",   "C");
    m.put("-..",    "D");
    m.put(".",      "E");
    …
    m.put("----.",  "9");
    MORSE_ALPHABET = Collections.unmodifiableMap(m);
}

我不喜欢把输入分成单词,把单词分成字符。由于您使用的是正则表达式,所以遵循成语 (不幸的是使用StringBuffer而不是StringBuilder)是个好主意。

有一种方法可以获得缓冲区大小的慷慨估计,所以这样做是个好主意。

代码语言:javascript
复制
private static final Pattern PATTERN = Pattern.compile("([.-]+)| ( ?)");

public static String decode(String morse) {
    StringBuffer decoded = new StringBuffer(morse.length() / 2);
    Matcher m = PATTERN.matcher(morse);
    while (m.find()) {
        String out = MORSE_ALPHABET.get(m.group(1));
        m.appendReplacement(decoded, out != null ? out : m.group(2));
    }
    return decoded.toString();
}
票数 1
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/135132

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档