Decode the Morse Code From Code Wars:


  This kata is part of a series on the Morse code. After you solve this kata, you may move to the next one.
  
  In this kata you have to write a simple Morse code decoder. While the Morse code is now mostly superceded by voice and digital data communication channels, it still has its use in some applications around the world.
  The Morse code encodes every character as a sequence of "dots" and "dashes". For example, the letter A is coded as ·−, letter Q is coded as −−·−, and digit 1 is coded as ·−−−−. The Morse code is case-insensitive, traditionally capital letters are used. When the message is written in Morse code, a single space is used to separate the character codes and 3 spaces are used to separate words. For example, the message HEY JUDE in Morse code is ···· · −·−− ·−−− ··− −·· ·.
  
  NOTE: Extra spaces before or after the code have no meaning and should be ignored.
  
  In addition to letters, digits and some punctuation, there are some special service codes, the most notorious of those is the international distress signal SOS (that was first issued by Titanic), that is coded as ···−−−···. These special codes are treated as single special characters, and usually are transmitted as separate words.
  
  Your task is to implement a function that would take the morse code as input and return a decoded human-readable string.
  
  For example:

decodeMorse('.... . -.--   .--- ..- -.. .')
#should return "HEY JUDE"

  
  NOTE: For coding purposes you have to use ASCII characters . and -, not Unicode characters.
  
  The Morse code table is preloaded for you as a dictionary, feel free to use it:
  
  Coffeescript/C++/Go/JavaScript/PHP/Python/Ruby/TypeScript: MORSE_CODE['.--']
  C#: MorseCode.Get(".--") (returns string)
  Elixir: morse_codes variable
  Haskell: morseCodes ! ".--" (Codes are in a Map String String)
  Java: MorseCode.get(".--")
  Kotlin: MorseCode[".--"] ?: "" or MorseCode.getOrDefault(".--", "")
  Rust: self.morse_code
  All the test strings would contain valid Morse code, so you may skip checking for errors and exceptions. In C#, tests will fail if the solution code throws an exception, please keep that in mind. This is mostly because otherwise the engine would simply ignore the tests, resulting in a "valid" solution.
  
  Good luck!
  
  After you complete this kata, you may try yourself at Decode the Morse code, advanced.


I wrote a program that works, but it was essentially done with ad hoc patches to cover the edge cases/exceptions the program initially didn't cover. I'd appreciate a critique of my code, such as best practices and the program logic itself.

# "Code Wars: Decode the Morse Code"

def decodeMorse(morse_code):
    clear_text = ''
    char = ''
    index = 0
    length = len(morse_code)
    delim1 = " "    # Next character delimiter.
    delim2 = "   "  # Next word delimiter. 
    while index &lt; (length):   
        if morse_code[index] != delim1:
            # Build the character to be added to the clear text.
            char += morse_code[index]
        else:
            # When the delimiter is encountered.
            if char != '':
                # To cover the program encountering erroneous whitespace. 
                clear_text += MORSE_CODE[char]
                    # Add said character to clear text
                char = ''
                    # Reset "char".
                if index &lt; (length-2):
                    # If it is possible to encounter a space.
                    if morse_code[index:(index+3)] == delim2:
                        # When a space is encountered.
                        clear_text += " "
                        index += 2
                        if index == length-1:
                            # If the last character in the code is a space, assign a control value to "char"
                            char = ""
        index += 1

    if char != "":
        # If the last character isn't a space.
        clear_text += MORSE_CODE[char]
            # Add the final character to the clear text.
    return clear_text
Iterating in Python

In Python if you find yourself writing something like:

while index &lt; (length):   


There is good chance you are not writing Pythonic code.  Looping over an index is just not needed that often.  I will start with showing some ways to improve your code.  And then at the end will show a more Pythonic solution.

I would suggest changing your looping statement to:

for index, di_dah in enumerate(morse_code.strip() + ' '):


enumerate() is used to iterate over an object and give the index of of the current element.  The str.strip() removes leading and trailing spaces, and the + ' ' at the end removes the need special casing after the loop.  This fairly simple change can greatly simplify the code needed inside the loop:

def decodeMorse2(morse_code):
    clear_text = ''
    char = ''

    for index, di_dah in enumerate(morse_code.strip() + ' '):
        if di_dah != ' ':
            char += di_dah
        elif char:
            clear_text += MORSE_CODE[char]
            char = ''
            if index &lt; len(morse_code) - 2:
                if morse_code[index: index + 3] == '   ':
                    clear_text += " "

    return clear_text    


More Pythonic?

I don't have access to the test cases, but I read the spec I think this would do the job:

def decodeMorse(morse_code):
    return ' '.join(
        ''.join(MORSE_CODE[char] for char in word.split())
        for word in morse_code.strip().split('   ')
    )


How does this work?

This code uses two nested loops in the form of generator expressions.  It uses str.split() to initially split the words in the outer loop and then again to split the characters in the inner loop.  Then does a character lookup and finally uses str.join() to build the sentence.