Search code examples
pythonpython-3.xmorse-code

Why does my Morse Code decoding tool not find any subsequent characters?


I am working on a Morse Code encoding/ decoding tool. I have completed the encoder, and I'm working on the decoder. Currently the decoding function "MorseCodeDecoder(MSG)" can decode a single letter at a time. It does this by checking every character in a string one by one and copying them to the variable, "EncodedLetter". The program checks each character to see if it is a space, if it is the program identifies this a gap between letter, for example: MSG = ".... .." -*the function runs*- EncodedLetter = "....". Then that value is back searched through a dictionary(using lists) to find what EncodedLetter's key whould be, in this case it's "H", the program also checks for double spaces which represent the space between two words. At this point in time it may sound fully functional; however after finding one encoded letter it can't find another, so earlier ".... .." it can't find ".." even though I reset the variable after it successfully decodes a letter.

MorseCodeDictionary = {' ': ' ', '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': '-----'}

def MorseCodeEncoder(MSG):
    EncodedMSG = f"""Encoded Message:
"""
    MSG = MSG.upper()
    for i in range(0, len(MSG), 1):
        Encode = (MSG[i])
        EncodedMSG = f"{EncodedMSG} {(MorseCodeDictionary.get(Encode))}"
    return EncodedMSG
def MorseCodeDecoder(MSG):
    DecodedMSG = f"""Decoded Message:
"""
    MSG = MSG.upper()
    DecodedWord = ''
    DecodedLetter = ''
    EncodedLetter = ''
    for i in range(0, len(MSG)):
        DecodedLetter = ''
        Decode = (MSG[i])
        try:    
          if (MSG[i + 1]) == ' ':
            EncodedLetter = f"{EncodedLetter + (MSG[i])}"
            DecodedLetter = list(MorseCodeDictionary.keys())[list(MorseCodeDictionary.values()).index(EncodedLetter)]
            DecodedWord = DecodedWord + DecodedLetter
            EncodedLetter = ''
            DecodedMSG = f"{DecodedMSG} {DecodedWord}"

          elif (MSG[i + 1]) + (MSG[i + 2]) == '  ':
                DecodedWord = ''

          else:
            EncodedLetter = f"{EncodedLetter + (MSG[i])}"
            
        except (ValueError,IndexError):
          pass
        
    return DecodedMSG
    
Loop = 1
while Loop == 1:
    Choice = str(input("""[1] Encode, or [2] decode?
"""))
    if Choice == '1':
        MSG = str(input("""Type the message you would like to encode. Do not use puncuation.
"""))
        EncodedMSG = (MorseCodeEncoder(MSG))
        print (EncodedMSG)
    elif Choice == '2':
        MSG = str(input("""Type what you wish to decode.
"""))
        DecodedMSG = (MorseCodeDecoder(MSG))
        print (DecodedMSG)
    else:
        print ('1, or 2')

Solution

  • Instead of blundering about with appending to strings and picking out each character from your encoded string to form a morse-code letter, you can just use str.join() and str.split()! Also, I suggest separating your encoded morse code letters by a character that cannot be a part of a correctly encoded string, such as /. This way, you are sure that all spaces in the string are a space and all slashes in the string are letter separators. First, let's define the dictionaries for both encoding and decoding

    en_to_morse = {' ': ' ', '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': '-----'}
    
    morse_to_en = {v: k for k, v in en_to_morse.items()} # Reverse lookup for encoder
    

    The morse_to_en dictionary can be created simply by reversing the keys and values in the en_to_morse dictionary. These two could be combined, since they do not have any common keys (except space, which doesn't really matter because it remains the same), but I'm going to keep them separate for this example.

    Then, you can write the encoder function like so:

    def MorseEncode(msg):
        morse_msg = [] # make an empty list to contain all our morse symbols
        for char in msg.upper(): # Convert msg to uppercase. Then iterate over each character
            morse_char = en_to_morse[char] # Get the translation from the dictionary
            morse_msg.append(morse_char)   # Append the translation to the list
        return '/'.join(morse_msg)   # Join symbols with a '/'
    

    The decoder function is just the reverse of the encoder function.

    def MorseDecode(msg):
        morse_chars = msg.split("/") # Split at '/'
        en_msg = ""                  # Empty message string 
        for char in morse_chars:     # Iterate over each symbol in the split list
            en_char = morse_to_en[char]  # Translate to English
            en_msg += en_char            # Append character to decoded message
        return en_msg  
    

    To run this:

    encoded = MorseEncode("Hello World") # gives '...././.-../.-../---/ /.--/---/.-./.-../-..'
    
    decoded = MorseDecode(encoded) # gives 'HELLO WORLD'
    

    You lose case-information because Morse code doesn't separate symbols for have upper/lower case characters.


    You could write your functions as one-liners too:

    def MorseEncode(msg):
        return '/'.join(en_to_morse[char] for char in msg.upper())
    
    def MorseDecode(msg):
        return ''.join(morse_to_en[char] for char in msg.split('/'))