1

I am trying to convert a string String input; to morse code and back. I am having a hard time figuring out which method to use and also how to use it. String I am trying to convert to morse code: SOS, which should translate to ...---..., and from morse code to English: ...---... - SOS.

One way I tried is using two arrays, String[] alpha = {A-Z0-9} and String[] morse = {morse patterns}. Then I tried splitting String input into an array, to compare each character in String input with each character in String[] alpha and storing each index in an indexArray[]. I used inputArray= input.split("", -1);

Finally with some for loops and if statements I tried to use the indexes I wanted to find of the characters of the string, to find the morse code in String[] morse.

What I tried above does not work for words, but works for one character (code below). It fails and I cannot figure out how to fix it that way. Is this even the best way to do this? Or HashMap?

Then I tried using a HashMap with the English characters as key, and morse as value.

Which way is the best way to convert English string to Morse code and Morse code to English string? Arrays or HashMap?

Arrays:

private String[] alpha = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J",
    "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V",
    "W", "X", "y", "z", "1", "2", "3", "4", "5", "6", "7", "8",
"9", "0", " "};

private String[] morse = {".-", "-...", "-.-.", "-..", ".", "..-.", "--.",
    "....", "..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.",
    "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-",
    "-.--", "--..", ".----", "..---", "...--", "....-", ".....",
"-....", "--...", "---..", "----.", "-----", "|"};

Broken for loop I was working on and couldn't figure out how to do it:

public int[] indexOfArray(String englishInput) {
    englishArray = englishInput.split("", -1);
    for (int j = 0; j < englishArray.length; j++) {
        for (int i = 0; i < alpha.length; i++) {
            if (alpha[i].equals(englishArray[j])) {
                indexArray[i] = i;
            }
        }
    }
    return indexArray;
}

This works for just one character (character to morse code):

public int indexOfArrayOld(String englishInput) {
    for (int i = 0; i < alpha.length; i++) {
        if (alpha[i].equals(englishInput)) {
            indexOld = i;
        }
    }
    return indexOld;
}

public String stringToMorseOld(int dummyIndex) {
    String morseCo = morse[dummyIndex];
    return morseCo;
}

HashMap:

private static HashMap<String, String>; alphaMorse = new HashMap<String, String>();

static {
    alphaMorse.put("A", ".-");
    alphaMorse.put("B", "-...");
    alphaMorse.put("C", "-.-.");
    alphaMorse.put("D", "-..");
    alphaMorse.put("E", ".");
    alphaMorse.put("F", "..-.");
    alphaMorse.put("G", "--.");
    alphaMorse.put("H", "....");
    alphaMorse.put("I", "..");
    alphaMorse.put("J", ".---");
    alphaMorse.put("K", "-.-");
    alphaMorse.put("L", ".-..");
    alphaMorse.put("M", "--");
    alphaMorse.put("N", "-.");
    alphaMorse.put("O", "---");
    alphaMorse.put("P", ".--.");
    alphaMorse.put("Q", "--.-");
    alphaMorse.put("R", ".-.");
    alphaMorse.put("S", "...");
    alphaMorse.put("T", "-");
    alphaMorse.put("U", "..-");
    alphaMorse.put("V", "...-");
    alphaMorse.put("W", ".--");
    alphaMorse.put("X", "-..-");
    alphaMorse.put("y", "-.--");
    alphaMorse.put("z", "--..");
    alphaMorse.put("1", ".----");
    alphaMorse.put("2", "..---");
    alphaMorse.put("3", "...--");
    alphaMorse.put("4", "....-");
    alphaMorse.put("5", ".....");
    alphaMorse.put("6", "-....");
    alphaMorse.put("7", "--...");
    alphaMorse.put("8", "---..");
    alphaMorse.put("9", "----.");
    alphaMorse.put("0", "-----");
    alphaMorse.put(" ", "|");
}
Kevin Panko
  • 8,356
  • 19
  • 50
  • 61
MOTIVECODEX
  • 2,624
  • 14
  • 43
  • 78

6 Answers6

1

i would think, ideally you have a two-dimensional array such as:

    String[][] morseArray = new String[][] {{ "S" , "..." }, { "O", "---" }}; 

and then, if you're looking for speed & ease of lookup, you might want to have two maps:

private Map<String,String> enToMorse;
private Map<String,String> morseToEn;

and some private method to retrieve them:

private Map<String,String> getMorseToEnMap() {
    if(morseToEn==null) {
        morseToEn = new HashMap<String,String>();
        for(String[] x : morseArray) {
            morseToEn.put(x[1], x[0]);
        }
    }
    return morseToEn;
}

then you can just go:

 Map<String,String> morse = getMorseToEn();
 String x = morse.get("...");
 [...]

the benefit being: on the one hand, you have an easy way to define your mapping - two separate arrays are a lot more difficult to keep in sync - while on the other hand, maps would be the fastest and easiest way to look up stuff like this.

rmalchow
  • 2,689
  • 18
  • 31
  • Should Map morse = getMorseToEn(); not be getMorseToEnMap()? Because I get an error with getMorseToEn() cannot resolve method. – MOTIVECODEX May 08 '15 at 21:10
  • I still cannot fix it, error says cannot find symbol on morse = getMorseToEn(); – MOTIVECODEX May 08 '15 at 21:24
  • Am I doing something wrong? https://ideone.com/WPqubr – MOTIVECODEX May 08 '15 at 21:30
  • made everything static and it works now, but the problem is it only works for a single morse and not for ...---... example SOS. – MOTIVECODEX May 08 '15 at 22:01
  • the "main" method is (and should be) static. in your case, everything else should not (maybe the 2d array can be "static final" ... anyways. i suggest you read up on the meaning of static and what the main method is supposed to do: http://stackoverflow.com/questions/146576/why-is-the-java-main-method-static – rmalchow May 09 '15 at 01:21
1

Use a Hashmap and get methods to compare them, finally append the key or value to a string:

public String stringToMorse(String str){
    String morse = "";
    for(char s: str.toCharArray()){
        morse += (String) Hashmap.get(s)+" ";
    }
    return morse;
}

for the other one use this method instead of get():

public static Object getKeyFromValue(Map hm, Object value) {
    for (Object o : hm.keySet()) {
      if (hm.get(o).equals(value)) {
        return o;
      }
    }
    return null;
}
Moises Zermeño
  • 763
  • 1
  • 6
  • 18
  • 1
    Don't forget to add a delimiter if decoding the morse String is necessary - otherwise there's no way to distinguish some values (is `---` 3 `-`?) – copeg May 08 '15 at 21:06
0

Efficiency-wise i would recomend the paralel array structure. I made a demo of those methods, I am not an efficiency wizard so nested loop might not be ideal here, or i may have some other flaws.

Anyway here the example class:

public class MorseTranslator {
private char[] alpha = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
        'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
        'X', 'y', 'z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
        ' ' };//Changed this to char to save some memory and to help my methods :3

private String[] morse = { ".-", "-...", "-.-.", "-..", ".", "..-.", "--.",
        "....", "..", ".---", "-.-", ".-..", "--", "-.", "---", ".--.",
        "--.-", ".-.", "...", "-", "..-", "...-", ".--", "-..-", "-.--",
        "--..", ".----", "..---", "...--", "....-", ".....", "-....",
        "--...", "---..", "----.", "-----", "|" };

private String toMorse(String text) {
    char[] characters = text.toUpperCase().toCharArray();
    StringBuilder morseString = new StringBuilder();
    for (char c : characters) {
        for (int i = 0; i < alpha.length; i++) {
            if (alpha[i] == c) {
                morseString.append(morse[i]+" ");
                break; 
            }
        }
    }
    return morseString.toString();
}

private  String fromMorse(String text){
    String[] strings = text.split(" ");
    StringBuilder translated = new StringBuilder();
    for(String s : strings){
        for(int i=0; i<morse.length; i++){
            if(morse[i].equals(s)){
                translated.append(alpha[i]);
                break;
            }
        }
    }
    return translated.toString();
}

public MorseTranslator(){
    String input = "Hello there";
    String morse = toMorse(input);
    String translated = fromMorse(morse);
    System.out.println("Input: "+input);
    System.out.println("Morse: "+morse);
    System.out.println("Back From morse: "+translated);
}
}

The code above demonstrates one possible way you can do it :- ) Hopefully that helped.

fill͡pant͡
  • 1,147
  • 2
  • 12
  • 24
  • 1
    `Efficiency-wise i would recomend the paralel array structure` Efficiency-wise, the Map provides constant time performance. This is relative to the parallel array's linear time (worst case). – copeg May 08 '15 at 21:01
  • why are parallel arrays more efficient than maps and/or 2d arrays? (two separate questions, really) – rmalchow May 08 '15 at 21:03
  • This is the only code I can get working. Is this efficient, or is HashMap better? – MOTIVECODEX May 08 '15 at 22:32
  • @copeg as far as i am concerned, arrays take a lot less in ram than a map but i might be wrong so please correxct me :D – fill͡pant͡ May 09 '15 at 07:39
0

Since you don't say what exactly does not work, I have to guess. Maybe the problem is the String.equals() method is case-sensitive, that is "X" and "x" are not the same. However, you seem to mix capital letters and non-capital letters, so that might be the problem. Does your method work when you replace equals with equalsIgnoreCase?

Some more pointers:

First, don't use strings for characters. You can simply use char which can hold a single character.

Second, do not use two arrays to store an array of pairs of objects. Maintaining two arrays is cumbersome and error-prone. If you want to use an array, then define a class which holds a character and a morse code string and define an array of those:

static class MorseMapping {
    char character;
    String morseCode;
    MorseMapping(char ch, String mc) {
        character = ch;
        morseCode = mc;
    }
}

static MorseMapping[] mappings = new MorseMapping[] {
    new MorseMapping('A', '.-'),
    \\ etc.
}

Third, personally I dislike using one map, because conceptually you do not want to map in one direction, but in both. Instead, use two maps, one from characters to morse codes and one from morse codes to hash maps. You can initialize them as follows:

static Map<String,Character> charToMorseMap;
static Map<Character,String> morseToCharMap;

private static void addPair(String morse, char ch) {
    charToMorseMap.put(ch, morse);
    morseToCharMap.put(morse, ch);
}

static {
    charToMorseMap = new HashMap<>();
    MorseToCharMap = new HashMap<>();
    // add all the characters
}

Alternatively, you can use a BiMap implementation which is present in various open-source class libraries, for example Google Guava.

By the way, you cannot put morse code . For example, ".--." could be the letter P, or it also could mean "AN", "WE", and a number of other strings. So, when translating English to Morse code, don't forget to add spaces to seperate the letters.

Hoopje
  • 12,677
  • 8
  • 34
  • 50
0

Encapsulate morse-english pair inside class, something like this:

public class EnglishMorseLetter {

  private String englishLetter;
  private String morseLetter;

public MorseLetter(String english, String morse){
    this.englishLetter = english;
    this.morseLetter = morse;
}

public String getEnglishLetter() {
    return englishLetter;
}
public void setEnglishLetter(String englishLetter) {
    this.englishLetter = englishLetter;
}
public String getMorseLetter() {
    return morseLetter;
}
public void setMorseLetter(String morseLetter) {        
    this.morseLetter = morseLetter;
}

}

Encapsulate dictionary with predefined values inside static class, something like this:

public class Dictionary {

    private static List<MorseLetter> dictionary = new ArrayList<MorseLetter>();

    static {
        dictionary.add(new MorseLetter("", ""));
        dictionary.add(new MorseLetter("A", ".-"));
        dictionary.add(new MorseLetter("B", "-..."));
        dictionary.add(new MorseLetter("C", "-.-."));
        dictionary.add(new MorseLetter("D", "-.."));
        dictionary.add(new MorseLetter("E", "."));
        dictionary.add(new MorseLetter("F", "..-."));
        dictionary.add(new MorseLetter("G", "--."));
        dictionary.add(new MorseLetter("H", "...."));
        dictionary.add(new MorseLetter("I", ".."));
        dictionary.add(new MorseLetter("J", ".---"));
        dictionary.add(new MorseLetter("K", "-.-"));
        dictionary.add(new MorseLetter("L", ".-.."));
        dictionary.add(new MorseLetter("M", "--"));
        dictionary.add(new MorseLetter("N", "-."));
        dictionary.add(new MorseLetter("O", "---"));
        dictionary.add(new MorseLetter("P", ".--."));
        dictionary.add(new MorseLetter("Q", "--.-"));
        dictionary.add(new MorseLetter("R", ".-."));
        dictionary.add(new MorseLetter("S", "..."));
        dictionary.add(new MorseLetter("T", "-"));
        dictionary.add(new MorseLetter("U", "..-"));
        dictionary.add(new MorseLetter("V", "...-"));
        dictionary.add(new MorseLetter("W", ".--"));
        dictionary.add(new MorseLetter("X", "-..-"));
        dictionary.add(new MorseLetter("y", "-.--"));
        dictionary.add(new MorseLetter("z", "--.."));
        dictionary.add(new MorseLetter("1", ".----"));
        dictionary.add(new MorseLetter("2", "..---"));
        dictionary.add(new MorseLetter("3", "...--"));
        dictionary.add(new MorseLetter("4", "....-"));
        dictionary.add(new MorseLetter("5", "....."));
        dictionary.add(new MorseLetter("6", "-...."));
        dictionary.add(new MorseLetter("7", "--..."));
        dictionary.add(new MorseLetter("8", "---.."));
        dictionary.add(new MorseLetter("9", "----."));
        dictionary.add(new MorseLetter("0", "-----"));
        dictionary.add(new MorseLetter(" ", "|"));
    }


    public static MorseLetter english2Morse(MorseLetter letter){
        for(MorseLetter tempLetter : dictionary){
            if(letter.getEnglishLetter().equalsIgnoreCase(tempLetter.getEnglishLetter())){
                letter.setMorseLetter(tempLetter.getMorseLetter());
                break;
            }
        }

        return letter;

    }


    public static MorseLetter morse2English(MorseLetter letter){
        for(MorseLetter tempLetter : dictionary){
            if(letter.getMorseLetter().equalsIgnoreCase(tempLetter.getMorseLetter())){
                letter.setEnglishLetter(tempLetter.getEnglishLetter());
                break;
            }
        }

        return letter;

    }

}

For MCVE I've done it with an List but for efficiency I'd like to advise to use two different sorted Maps with English-Morse pairs and Morse-English pairs.

Also encapsulate word inside class like that:

public class EnglishMorseWord{

    private List<EnglishMorseLetter> word;

    public String getEnglishWord(){
        //...you combine your word property into english word
    }

    public void setEnglishWord(String englishWord){
        //...you parse your word and fill word property by using Dictionary
    }

    public String getMorseWord(){
        //...you combine your word property into morse word

    }

}
Anatoly
  • 5,056
  • 9
  • 62
  • 136
0

Another good approach is to use an enum

public enum MorseCode {
    A('A', ".-"),
    B('B', "-..."),
    C('C', "-.-."),
    // ...
    D8('8', "---.."),
    D9('9', "----."),
    D0('0', "-----");

    private static final Map<String, MorseCode> FromCode = new HashMap<>(MorseCode.values().length);
    private static final Map<Character, MorseCode> FromChar = new HashMap<>(MorseCode.values().length);
    static {
        for (MorseCode value : values()) {
            FromCode.put(value.toCode(), value);
            FromChar.put(value.toChar(), value);
        }
    }

    public static MorseCode fromCode(String code) {
        return FromCode.get(code);
    }

    public static MorseCode fromChar(Character character) {
        return FromChar.get(character);
    }

    private final String Code;
    private final Character Character;
    private MorseCode(Character character, String code) {
        Code = code;
        Character = character;
    }

    public char toChar() {
        return Character;
    }

    public String toCode() {
        return Code;
    }
}
Morgen
  • 1,010
  • 1
  • 11
  • 15