Wednesday, August 24, 2022

Morse Code Library

Morse code has been on my mind every now and then for the past several years. I don't write as much code as I used to since I left the software development industry, but today I decided it was time to write functions to encode and decode morse.

First, let's define an array to map the encodings for each character.

  1. $morse = array(
  2. " " => "/",
  3. "A" => ".-",
  4. "B" => "-...",
  5. "C" => "-.-.",
  6. "D" => "-..",
  7. "E" => ".",
  8. "F" => "..-.",
  9. "G" => "--.",
  10. "H" => "....",
  11. "I" => "..",
  12. "J" => ".---",
  13. "K" => "-.-",
  14. "L" => ".-..",
  15. "M" => "--",
  16. "N" => "-.",
  17. "O" => "---",
  18. "P" => ".--.",
  19. "Q" => "--.-",
  20. "R" => ".-.",
  21. "S" => "...",
  22. "T" => "-",
  23. "U" => "..-",
  24. "V" => "...-",
  25. "W" => ".--",
  26. "X" => "-..-",
  27. "Y" => "-.--",
  28. "Z" => "--..",
  29. "0" => "-----",
  30. "1" => ".----",
  31. "2" => "..---",
  32. "3" => "...--",
  33. "4" => "....-",
  34. "5" => ".....",
  35. "6" => "-....",
  36. "7" => "--...",
  37. "8" => "---..",
  38. "9" => "----.",
  39. "." => ".-.-.-",
  40. "," => "--..--",
  41. "?" => "..--..",
  42. "'" => ".----.",
  43. "!" => "-.-.--",
  44. "/" => "-..-.",
  45. "(" => "-.--.",
  46. ")" => "-.--.-",
  47. "&" => ".-...",
  48. ":" => "---...",
  49. ";" => "-.-.-.",
  50. "=" => "-...-",
  51. "+" => ".-.-.",
  52. "-" => "-....-",
  53. "_" => "..--.-",
  54. "\"" => ".-..-.",
  55. "$" => "...-..-",
  56. "@" => ".--.-.",
  57. );

This covers almost all possible morse characters, with the exception of accented letters.

Next, we need a function to encode messages.

  1. function morseEncodeMessage($message)
  2. {
  3. global $morse;
  4. $result = "";
  5. for ($i = 0; $i <= strlen($message) - 1; $i++)
  6. {
  7. $character = strtoupper(substr($message, $i, 1));
  8. $result .= (array_key_exists($character, $morse) ? $morse[$character] : "........") . " ";
  9. }
  10. $result = rtrim($result);
  11. return $result;
  12. }
We're looping through the message, one character at a time. Lowercase characters are turned into uppercase characters. We check the global array to see if there's a corresponding key, and if so we get the value associated with that key. If the character can't be found, we convert it to a series of eight dots to indicate that an error has occurred. Each encoded character is separated by a space; an extra trailing space is removed before we return the result. Spaces between words are turned into forward slashes.

Now we need a way of decoding messages.

  1. function morseDecodeMessage($message)
  2. {
  3. global $morse;
  4. $result = "";
  5. $characters = explode(" ", $message);
  6. foreach ($characters as &$character)
  7. {
  8. $result .= in_array($character, $morse, true) ? array_search($character, $morse, true) : "ERROR";
  9. }
  10. unset($character);
  11. return $result;
  12. }
We start by splitting the encoded message into an array, using the spaces between each letter as the separator. Then we loop through the local array and check the global array for each value. If the value is found, we retrieve the key, otherwise we indicate that an error has occurred.

Finally, let's write a unit test to make sure our code is working properly.

  1. function morseTest($message)
  2. {
  3. $testInput = $message;
  4. echo "Input:   " . strtoupper($testInput) . "\n";
  5. $testEncoded = morseEncodeMessage($testInput);
  6. echo "Encoded: " . $testEncoded . "\n";
  7. $testDecoded = morseDecodeMessage($testEncoded);
  8. echo "Decoded: " . $testDecoded . "\n";
  9. echo "Result:  Test " . ($testDecoded == strtoupper($testInput) ? "successful" : "failed") . "!\n";
  10. }
Nothing too complicated. Display the message before encoding, encode the message, display the encoded message, decode the message, display the decoded message, and compare the decoded message with the original.

If we execute the following:
morseTest("Hello world!");

We get this result:
Input:   HELLO WORLD!
Encoded: .... . .-.. .-.. --- / .-- --- .-. .-.. -.. -.-.--
Decoded: HELLO WORLD!
Result:  Test successful!