A Simple Python Morse Code Translator

Morse code was developed in telecommunications to encode the alphabetic characters in binary signals (“long” and “short”, or “1” and “0”).

Here’s the Morse code table:

Each character is mapped to its Morse code representation.

This tutorial shows you how to implement a simple Morse code translator in Python.

You can also play the explainer video as you read through the article:

The code is contributed by Finxter student Albrecht.

Goal: Given a string that is either Morse code or normal text. Write a function that transforms the string into the other language: Morse code should be translated to normal text. Normal text should be translated to Morse code.

Output Example: Create a function morse(txt) that takes an input string argument txt and returns its translation:

>>> morse('python')
'.--. -.-- - .... --- -.'
>>> morse('.--. -.-- - .... --- -.')
>>> morse(morse('HEY'))

Note that Morse code doesn’t differentiate lowercase or uppercase characters. So you just use uppercase characters as default translation output.

Algorithm Idea: A simple algorithm is enough to solve the problem:

  • Detect if a string is Morse code or normal text. The simple but not perfect solution is to check if the first character is either the dot symbol '.' or the minus symbol '-'. Note that you can easily extend this by checking if all characters are either the dot symbol or the minus symbol (a simple regular expression will be enough).
  • Prepare a dictionary that maps all “normal text” symbols to their respective Morse code translations. Use the inverse dictionary (or create it ad-hoc) to get the inverse mapping.
  • Iterate over all characters in the string and use the dictionary to translate each character separately.

Implementation: Here’s the Python implementation of the above algorithm for Morse code translation:

def morse(txt):
    '''Morse code encryption and decryption'''
    d = {'A':'.-','B':'-...','C':'-.-.','D':'-..','E':'.',
         'Z':'--..', ' ':'.....'}
    translation = ''
    # Encrypt Morsecode
    if txt.startswith('.') or txt.startswith('−'):
        # Swap key/values in d:
        d_encrypt = dict([(v, k) for k, v in d.items()])
        # Morse code is separated by empty space chars
        txt = txt.split(' ')
        for x in txt:
            translation += d_encrypt.get(x)
    # Decrypt to Morsecode:
        txt = txt.upper()
        for x in txt:
            translation += d.get(x) + ' '
    return translation.strip()

# .--. -.-- - .... --- -.
print(morse('.--. -.-- - .... --- -.'))

Algorithmic complexity: The runtime complexity is linear in the length of the input string to be translated—one translation operation per character. Dictionary membership has constant runtime complexity. The memory overhead is also linear in the input text as all the characters have to be hold in memory.

Alternative Implementation: Albrecht also proposed a much shorter alternative:

def morse(txt):
    encrypt = {'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':'--..', ' ':'.....'}
    decrypt = {v: k for k, v in encrypt.items()}
    if '-' in txt:
        return ''.join(decrypt[i] for i in txt.split())
    return ' '.join(encrypt[i] for i in txt.upper())

# .--. -.-- - .... --- -.
print(morse('.--. -.-- - .... --- -.'))

It uses dict comprehension and generator expressions to make it much more concise.

Related article: Python Regex Superpower – The Ultimate Guide