编写一个程序,读取包含Morse代码的文件并输出转换。
.- .。。。-.-...…….,--
AV2WHIECX 45 BH3
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);
}
}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方法,以方便测试。
发布于 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了..。我更希望:
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将导致系统“刷新”每一行,这通常相当于程序时间的重要部分(超过一半?)。
类似地,在一次“吞咽”中读取整个输入文件通常比扫描仪或其他操作要快。
显然,理论上“巨大”的输入可能是一个问题,但我还没有在挑战中被这样的条件所伤害。
我会考虑使用gulp函数来读取整个文件--Java8 java.nio.files包可以在这里提供帮助,我可以选择:
List<String> data = Files.readAllLines(Paths.get(args[0]));将空字符串加载到解码例程以输出空格的技巧将允许您使用regex拆分并处理流中的每一行:
private static final Pattern charsplit = Pattern.compile(" ");然后:
String out = charsplit.splitAsStream(line)
.map(letter -> morseAlphabet.get(letter))
.collect(Collectors.joining(""));然后,可以用换行符将该out附加到输出缓冲区.因此,整个过程看起来有点像(未经测试-参见工作代码的结论):
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中是无法完成的。
下面是完整的代码:
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);
}
}发布于 2016-07-19 19:06:13
作为一个不变的常量,morseAlphabet映射会更好:
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)是个好主意。
有一种方法可以获得缓冲区大小的慷慨估计,所以这样做是个好主意。
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();
}https://codereview.stackexchange.com/questions/135132
复制相似问题