+/*
+ * Morse Code Translator Java class
+ *
+ * Copyright (C) 2015 Antonio Ospite <ao2@ao2.it>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * ---------------------------------------------------------------------------
+ *
+ * The code was initially based on:
+ *
+ * - Morse.java by Stephen C Phillips:
+ * http://morsecode.scphillips.com/Morse.java
+ * Copyright (C) 1999-2004 Stephen C Phillips <steve@scphillips.com>
+ *
+ * - NMorse.java by Michael R Ditto:
+ * http://www.omnicron.com/~ford/java/NMorse.java
+ * Copyright (C) 2001 Michael R Ditto <ford@omnicron.com>
+ *
+ * ---------------------------------------------------------------------------
+ *
+ * The specification of the International Morse Code is in ITU-R M.1677-1
+ * (10/2009), Annex 1.
+ *
+ * The terminology used here may differ from the one used in some other
+ * places, so here is some nomenclature:
+ *
+ * symbol: one of . (dot), - (dash), ' ' (signal separator),
+ * '/' (word separator)
+ *
+ * character: a letter of the alphabet, a number, a punctuation mark, or
+ * a ' ' (text word separator)
+ *
+ * signal: a sequence of . and - symbols which encode a character,
+ * or a '/' (Morse word separator)
+ *
+ * word: a sequence of characters not containing a ' ', or
+ * a sequence of signals not containing a '/'
+ *
+ * text: a sequence of characters
+ *
+ * morse: a sequence of signals separated by ' '
+ *
+ * NOTE:
+ * signals are separated by a ' ' (signal separator), characters are not
+ * separated one from the other.
+ *
+ * This class defines a subset of the signals in Section 1 of the
+ * aforementioned specification, plus a word space, and it does not make
+ * assumptions about their actual transmission.
+ */
+
+package it.ao2.util.morse;
+
+import java.util.Arrays;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Iterator;
+import java.util.Locale;
+
+public class MorseTranslator {
+ private Hashtable<Character, String> mSignalsTable;
+ private Hashtable<String, Character> mCharactersTable;
+
+ public MorseTranslator() {
+ mSignalsTable = new Hashtable<Character, String>();
+
+ // Letters
+ mSignalsTable.put(Character.valueOf('a'), ".-");
+ mSignalsTable.put(Character.valueOf('b'), "-...");
+ mSignalsTable.put(Character.valueOf('c'), "-.-.");
+ mSignalsTable.put(Character.valueOf('d'), "-..");
+ mSignalsTable.put(Character.valueOf('e'), ".");
+ mSignalsTable.put(Character.valueOf('f'), "..-.");
+ mSignalsTable.put(Character.valueOf('g'), "--.");
+ mSignalsTable.put(Character.valueOf('h'), "....");
+ mSignalsTable.put(Character.valueOf('i'), "..");
+ mSignalsTable.put(Character.valueOf('j'), ".---");
+ mSignalsTable.put(Character.valueOf('k'), "-.-");
+ mSignalsTable.put(Character.valueOf('l'), ".-..");
+ mSignalsTable.put(Character.valueOf('m'), "--");
+ mSignalsTable.put(Character.valueOf('n'), "-.");
+ mSignalsTable.put(Character.valueOf('o'), "---");
+ mSignalsTable.put(Character.valueOf('p'), ".--.");
+ mSignalsTable.put(Character.valueOf('q'), "--.-");
+ mSignalsTable.put(Character.valueOf('r'), ".-.");
+ mSignalsTable.put(Character.valueOf('s'), "...");
+ mSignalsTable.put(Character.valueOf('t'), "-");
+ mSignalsTable.put(Character.valueOf('u'), "..-");
+ mSignalsTable.put(Character.valueOf('v'), "...-");
+ mSignalsTable.put(Character.valueOf('w'), ".--");
+ mSignalsTable.put(Character.valueOf('x'), "-..-");
+ mSignalsTable.put(Character.valueOf('y'), "-.--");
+ mSignalsTable.put(Character.valueOf('z'), "--..");
+ // Figures
+ mSignalsTable.put(Character.valueOf('1'), ".----");
+ mSignalsTable.put(Character.valueOf('2'), "..---");
+ mSignalsTable.put(Character.valueOf('3'), "...--");
+ mSignalsTable.put(Character.valueOf('4'), "....-");
+ mSignalsTable.put(Character.valueOf('5'), ".....");
+ mSignalsTable.put(Character.valueOf('6'), "-....");
+ mSignalsTable.put(Character.valueOf('7'), "--...");
+ mSignalsTable.put(Character.valueOf('8'), "---..");
+ mSignalsTable.put(Character.valueOf('9'), "----.");
+ mSignalsTable.put(Character.valueOf('0'), "-----");
+ // Punctuation marks and miscellaneous signs
+ mSignalsTable.put(Character.valueOf('.'), ".-.-.-");
+ mSignalsTable.put(Character.valueOf(','), "--..--");
+ mSignalsTable.put(Character.valueOf(':'), "---...");
+ mSignalsTable.put(Character.valueOf('?'), "..--..");
+ mSignalsTable.put(Character.valueOf('\''), ".----.");
+ mSignalsTable.put(Character.valueOf('-'), "-....-");
+ mSignalsTable.put(Character.valueOf('/'), "-..-.");
+ mSignalsTable.put(Character.valueOf('('), "-.--.-");
+ mSignalsTable.put(Character.valueOf(')'), "-.--.-");
+ mSignalsTable.put(Character.valueOf('"'), ".-..-.");
+ mSignalsTable.put(Character.valueOf('='), "-...-");
+ mSignalsTable.put(Character.valueOf('+'), ".-.-.");
+ mSignalsTable.put(Character.valueOf('x'), "-..-");
+ mSignalsTable.put(Character.valueOf('@'), ".--.-.");
+
+ // Represent the word space as a signal with only one "/" symbol
+ mSignalsTable.put(Character.valueOf(' '), "/");
+
+ mCharactersTable = new Hashtable<String, Character>();
+
+ Enumeration<Character> list = mSignalsTable.keys();
+ while (list.hasMoreElements()) {
+ Character c = list.nextElement();
+ String s = mSignalsTable.get(c);
+ mCharactersTable.put(s, c);
+ }
+ }
+
+ public String sanitizeText(String text) {
+ String sanitizedText;
+
+ sanitizedText = text.toLowerCase(Locale.US);
+ sanitizedText = sanitizedText.replaceAll("[^a-z0-9.,:?\'/()\"=+;_$@ -]", "");
+ sanitizedText = sanitizedText.replaceAll("\\s+", " ");
+ return sanitizedText;
+ }
+
+ public String charToSignal(Character character) {
+ character = Character.toLowerCase(character);
+
+ if (mSignalsTable.containsKey(character)) {
+ return mSignalsTable.get(character);
+ } else {
+ return "";
+ }
+ }
+
+ public String textToMorse(String text, boolean sanitize) {
+ if (sanitize) {
+ text = sanitizeText(text);
+ }
+
+ StringBuffer morse = new StringBuffer();
+ for (int i = 0; i < text.length(); i++) {
+ //Character ch = Character.valueOf(text.charAt(i));
+ Character character = text.charAt(i);
+
+ morse.append(charToSignal(character));
+
+ if (i < text.length() - 1) {
+ morse.append(" ");
+ }
+ }
+
+ return morse.toString();
+ }
+
+ public String textToMorse(String text) {
+ return textToMorse(text, true);
+ }
+
+ public String sanitizeMorse(String morse) {
+ String sanitizedMorse;
+
+ sanitizedMorse = morse.replaceAll("_", "-");
+ sanitizedMorse = sanitizedMorse.replaceAll("[^\\-\\.\\/]", " ");
+ sanitizedMorse = sanitizedMorse.replaceAll("\\s+", " ");
+ sanitizedMorse = sanitizedMorse.replaceAll("( ?/ ?)+", " / ");
+ return sanitizedMorse;
+ }
+
+ public Character signalToCharacter(String signal) {
+ if (mCharactersTable.containsKey(signal)) {
+ return mCharactersTable.get(signal);
+ } else {
+ return '*';
+ }
+ }
+
+ public String morseToText(String morse, boolean sanitize) {
+ if (sanitize) {
+ morse = sanitizeMorse(morse);
+ }
+
+ StringBuffer text = new StringBuffer();
+ Iterator<String> signals = Arrays.asList(morse.split(" ")).iterator();
+ while (signals.hasNext()) {
+ String signal = signals.next();
+ text.append(signalToCharacter(signal));
+ }
+
+ return text.toString();
+ }
+
+ public String morseToText(String morse) {
+ return morseToText(morse, true);
+ }
+}