Decode the Morse Code

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
6
down vote

favorite












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 < (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 < (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









share|improve this question





























    up vote
    6
    down vote

    favorite












    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 < (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 < (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









    share|improve this question

























      up vote
      6
      down vote

      favorite









      up vote
      6
      down vote

      favorite











      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 < (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 < (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









      share|improve this question















      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 < (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 < (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






      python beginner python-3.x programming-challenge morse-code






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Sep 2 at 2:59









      200_success

      124k14144401




      124k14144401










      asked Sep 1 at 23:36









      Tobi Alafin

      1835




      1835




















          2 Answers
          2






          active

          oldest

          votes

















          up vote
          7
          down vote



          accepted










          Iterating in Python



          In Python if you find yourself writing something like:



          while index < (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 < 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.






          share|improve this answer




















          • I can't fully understand the More Pythonic code, but I would read up on Generator expressions and the documentation of the functions you used and try and reconstruct the more pythonic version myself.
            – Tobi Alafin
            Sep 2 at 13:21










          • +1 for enumerate, str.split(), str.join() and generator expressions. Maybe it would be even more pythonic to define a words-generator first and then joining them on the next line of code. Reasoning: "pythonic" is usually not only associated with clever use of built-in tools, but also with legibility, and your code basically has to be read from bottom to top, because you use word one line before defining it. Yes, this is very nitpicky and a bit philosophical, I really like your overall approach.
            – Niklas Mertsch
            Sep 3 at 17:55











          • @NiklasMertsch, Thanks. But a words generator would just be the .split(). It is unclear to me how defining that on a previous line helps here. Except in the case of a conditional, the use of word is always going to come before the definition of word in a generator (comprehension). I don't know how to structure a words generator to avoid that in this case.
            – Stephen Rauch
            Sep 3 at 18:12










          • You are actually right, there seems to be no elegant way to use and join nested generators. Should have put more thought into my previous comment. While your solution is kind of impressing in its shortness, I still would not call it very pythonic as this one expression you are returning does a lot of things at once that don't happen in the order of the lines of code.
            – Niklas Mertsch
            Sep 3 at 18:59










          • Using and reading generators and comprehensions does take some time to get used to. Practicing will help there. Good luck, and thanks again for the feedback.
            – Stephen Rauch
            Sep 3 at 19:02


















          up vote
          6
          down vote













          Since strings in Python are an immutable sequence type, building strings using += is not good practice, because it can lead to poor performance. Such concatenation may require the interpreter to allocate a new string and copy both the old and new parts into the new string (though CPython tries to avoid that when possible).



          I'd think of this as a string substitution exercise. String substitutions based on patterns can be done using regular expressions. The solution could be greatly simplified using re.sub():



          import re

          def decodeMorse(morse_code):
          return re.sub(
          '([.-]+)|(?<=[.-])( )(?=[.-])| *',
          lambda code: MORSE_CODE[code.group(1)] if code.group(1) else
          ' ' if code.group(2) else '',
          morse_code
          )


          The code above says:




          • ([.-]+) — For any sequence of one or more dots and/or dashes, perform the MORSE_CODE[…] lookup on that group.


          • (?<=[.-])( )(?=[.-]) — For any sequence of three spaces that is…




            • (?<=[.-]) — preceded by a dot or dash (a "positive lookbehind assertion"), and


            • (?=[.-]) — followed by a dot or dash (a "positive lookahead assertion")

            … then replace that group with a single space.




          •  * — Any other spaces should be replaced with nothing.

          It's unfortunate that the lookbehind and lookahead assertions are necessary, because the online test cases expect you to discard leading and trailing spaces. (An alternate technique you could use is to .strip() the input or the output.)






          share|improve this answer




















            Your Answer




            StackExchange.ifUsing("editor", function ()
            return StackExchange.using("mathjaxEditing", function ()
            StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
            StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
            );
            );
            , "mathjax-editing");

            StackExchange.ifUsing("editor", function ()
            StackExchange.using("externalEditor", function ()
            StackExchange.using("snippets", function ()
            StackExchange.snippets.init();
            );
            );
            , "code-snippets");

            StackExchange.ready(function()
            var channelOptions =
            tags: "".split(" "),
            id: "196"
            ;
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function()
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled)
            StackExchange.using("snippets", function()
            createEditor();
            );

            else
            createEditor();

            );

            function createEditor()
            StackExchange.prepareEditor(
            heartbeatType: 'answer',
            convertImagesToLinks: false,
            noModals: false,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: null,
            bindNavPrevention: true,
            postfix: "",
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            );



            );













             

            draft saved


            draft discarded


















            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f202958%2fdecode-the-morse-code%23new-answer', 'question_page');

            );

            Post as a guest






























            2 Answers
            2






            active

            oldest

            votes








            2 Answers
            2






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            7
            down vote



            accepted










            Iterating in Python



            In Python if you find yourself writing something like:



            while index < (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 < 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.






            share|improve this answer




















            • I can't fully understand the More Pythonic code, but I would read up on Generator expressions and the documentation of the functions you used and try and reconstruct the more pythonic version myself.
              – Tobi Alafin
              Sep 2 at 13:21










            • +1 for enumerate, str.split(), str.join() and generator expressions. Maybe it would be even more pythonic to define a words-generator first and then joining them on the next line of code. Reasoning: "pythonic" is usually not only associated with clever use of built-in tools, but also with legibility, and your code basically has to be read from bottom to top, because you use word one line before defining it. Yes, this is very nitpicky and a bit philosophical, I really like your overall approach.
              – Niklas Mertsch
              Sep 3 at 17:55











            • @NiklasMertsch, Thanks. But a words generator would just be the .split(). It is unclear to me how defining that on a previous line helps here. Except in the case of a conditional, the use of word is always going to come before the definition of word in a generator (comprehension). I don't know how to structure a words generator to avoid that in this case.
              – Stephen Rauch
              Sep 3 at 18:12










            • You are actually right, there seems to be no elegant way to use and join nested generators. Should have put more thought into my previous comment. While your solution is kind of impressing in its shortness, I still would not call it very pythonic as this one expression you are returning does a lot of things at once that don't happen in the order of the lines of code.
              – Niklas Mertsch
              Sep 3 at 18:59










            • Using and reading generators and comprehensions does take some time to get used to. Practicing will help there. Good luck, and thanks again for the feedback.
              – Stephen Rauch
              Sep 3 at 19:02















            up vote
            7
            down vote



            accepted










            Iterating in Python



            In Python if you find yourself writing something like:



            while index < (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 < 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.






            share|improve this answer




















            • I can't fully understand the More Pythonic code, but I would read up on Generator expressions and the documentation of the functions you used and try and reconstruct the more pythonic version myself.
              – Tobi Alafin
              Sep 2 at 13:21










            • +1 for enumerate, str.split(), str.join() and generator expressions. Maybe it would be even more pythonic to define a words-generator first and then joining them on the next line of code. Reasoning: "pythonic" is usually not only associated with clever use of built-in tools, but also with legibility, and your code basically has to be read from bottom to top, because you use word one line before defining it. Yes, this is very nitpicky and a bit philosophical, I really like your overall approach.
              – Niklas Mertsch
              Sep 3 at 17:55











            • @NiklasMertsch, Thanks. But a words generator would just be the .split(). It is unclear to me how defining that on a previous line helps here. Except in the case of a conditional, the use of word is always going to come before the definition of word in a generator (comprehension). I don't know how to structure a words generator to avoid that in this case.
              – Stephen Rauch
              Sep 3 at 18:12










            • You are actually right, there seems to be no elegant way to use and join nested generators. Should have put more thought into my previous comment. While your solution is kind of impressing in its shortness, I still would not call it very pythonic as this one expression you are returning does a lot of things at once that don't happen in the order of the lines of code.
              – Niklas Mertsch
              Sep 3 at 18:59










            • Using and reading generators and comprehensions does take some time to get used to. Practicing will help there. Good luck, and thanks again for the feedback.
              – Stephen Rauch
              Sep 3 at 19:02













            up vote
            7
            down vote



            accepted







            up vote
            7
            down vote



            accepted






            Iterating in Python



            In Python if you find yourself writing something like:



            while index < (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 < 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.






            share|improve this answer












            Iterating in Python



            In Python if you find yourself writing something like:



            while index < (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 < 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.







            share|improve this answer












            share|improve this answer



            share|improve this answer










            answered Sep 2 at 0:59









            Stephen Rauch

            3,74051530




            3,74051530











            • I can't fully understand the More Pythonic code, but I would read up on Generator expressions and the documentation of the functions you used and try and reconstruct the more pythonic version myself.
              – Tobi Alafin
              Sep 2 at 13:21










            • +1 for enumerate, str.split(), str.join() and generator expressions. Maybe it would be even more pythonic to define a words-generator first and then joining them on the next line of code. Reasoning: "pythonic" is usually not only associated with clever use of built-in tools, but also with legibility, and your code basically has to be read from bottom to top, because you use word one line before defining it. Yes, this is very nitpicky and a bit philosophical, I really like your overall approach.
              – Niklas Mertsch
              Sep 3 at 17:55











            • @NiklasMertsch, Thanks. But a words generator would just be the .split(). It is unclear to me how defining that on a previous line helps here. Except in the case of a conditional, the use of word is always going to come before the definition of word in a generator (comprehension). I don't know how to structure a words generator to avoid that in this case.
              – Stephen Rauch
              Sep 3 at 18:12










            • You are actually right, there seems to be no elegant way to use and join nested generators. Should have put more thought into my previous comment. While your solution is kind of impressing in its shortness, I still would not call it very pythonic as this one expression you are returning does a lot of things at once that don't happen in the order of the lines of code.
              – Niklas Mertsch
              Sep 3 at 18:59










            • Using and reading generators and comprehensions does take some time to get used to. Practicing will help there. Good luck, and thanks again for the feedback.
              – Stephen Rauch
              Sep 3 at 19:02

















            • I can't fully understand the More Pythonic code, but I would read up on Generator expressions and the documentation of the functions you used and try and reconstruct the more pythonic version myself.
              – Tobi Alafin
              Sep 2 at 13:21










            • +1 for enumerate, str.split(), str.join() and generator expressions. Maybe it would be even more pythonic to define a words-generator first and then joining them on the next line of code. Reasoning: "pythonic" is usually not only associated with clever use of built-in tools, but also with legibility, and your code basically has to be read from bottom to top, because you use word one line before defining it. Yes, this is very nitpicky and a bit philosophical, I really like your overall approach.
              – Niklas Mertsch
              Sep 3 at 17:55











            • @NiklasMertsch, Thanks. But a words generator would just be the .split(). It is unclear to me how defining that on a previous line helps here. Except in the case of a conditional, the use of word is always going to come before the definition of word in a generator (comprehension). I don't know how to structure a words generator to avoid that in this case.
              – Stephen Rauch
              Sep 3 at 18:12










            • You are actually right, there seems to be no elegant way to use and join nested generators. Should have put more thought into my previous comment. While your solution is kind of impressing in its shortness, I still would not call it very pythonic as this one expression you are returning does a lot of things at once that don't happen in the order of the lines of code.
              – Niklas Mertsch
              Sep 3 at 18:59










            • Using and reading generators and comprehensions does take some time to get used to. Practicing will help there. Good luck, and thanks again for the feedback.
              – Stephen Rauch
              Sep 3 at 19:02
















            I can't fully understand the More Pythonic code, but I would read up on Generator expressions and the documentation of the functions you used and try and reconstruct the more pythonic version myself.
            – Tobi Alafin
            Sep 2 at 13:21




            I can't fully understand the More Pythonic code, but I would read up on Generator expressions and the documentation of the functions you used and try and reconstruct the more pythonic version myself.
            – Tobi Alafin
            Sep 2 at 13:21












            +1 for enumerate, str.split(), str.join() and generator expressions. Maybe it would be even more pythonic to define a words-generator first and then joining them on the next line of code. Reasoning: "pythonic" is usually not only associated with clever use of built-in tools, but also with legibility, and your code basically has to be read from bottom to top, because you use word one line before defining it. Yes, this is very nitpicky and a bit philosophical, I really like your overall approach.
            – Niklas Mertsch
            Sep 3 at 17:55





            +1 for enumerate, str.split(), str.join() and generator expressions. Maybe it would be even more pythonic to define a words-generator first and then joining them on the next line of code. Reasoning: "pythonic" is usually not only associated with clever use of built-in tools, but also with legibility, and your code basically has to be read from bottom to top, because you use word one line before defining it. Yes, this is very nitpicky and a bit philosophical, I really like your overall approach.
            – Niklas Mertsch
            Sep 3 at 17:55













            @NiklasMertsch, Thanks. But a words generator would just be the .split(). It is unclear to me how defining that on a previous line helps here. Except in the case of a conditional, the use of word is always going to come before the definition of word in a generator (comprehension). I don't know how to structure a words generator to avoid that in this case.
            – Stephen Rauch
            Sep 3 at 18:12




            @NiklasMertsch, Thanks. But a words generator would just be the .split(). It is unclear to me how defining that on a previous line helps here. Except in the case of a conditional, the use of word is always going to come before the definition of word in a generator (comprehension). I don't know how to structure a words generator to avoid that in this case.
            – Stephen Rauch
            Sep 3 at 18:12












            You are actually right, there seems to be no elegant way to use and join nested generators. Should have put more thought into my previous comment. While your solution is kind of impressing in its shortness, I still would not call it very pythonic as this one expression you are returning does a lot of things at once that don't happen in the order of the lines of code.
            – Niklas Mertsch
            Sep 3 at 18:59




            You are actually right, there seems to be no elegant way to use and join nested generators. Should have put more thought into my previous comment. While your solution is kind of impressing in its shortness, I still would not call it very pythonic as this one expression you are returning does a lot of things at once that don't happen in the order of the lines of code.
            – Niklas Mertsch
            Sep 3 at 18:59












            Using and reading generators and comprehensions does take some time to get used to. Practicing will help there. Good luck, and thanks again for the feedback.
            – Stephen Rauch
            Sep 3 at 19:02





            Using and reading generators and comprehensions does take some time to get used to. Practicing will help there. Good luck, and thanks again for the feedback.
            – Stephen Rauch
            Sep 3 at 19:02













            up vote
            6
            down vote













            Since strings in Python are an immutable sequence type, building strings using += is not good practice, because it can lead to poor performance. Such concatenation may require the interpreter to allocate a new string and copy both the old and new parts into the new string (though CPython tries to avoid that when possible).



            I'd think of this as a string substitution exercise. String substitutions based on patterns can be done using regular expressions. The solution could be greatly simplified using re.sub():



            import re

            def decodeMorse(morse_code):
            return re.sub(
            '([.-]+)|(?<=[.-])( )(?=[.-])| *',
            lambda code: MORSE_CODE[code.group(1)] if code.group(1) else
            ' ' if code.group(2) else '',
            morse_code
            )


            The code above says:




            • ([.-]+) — For any sequence of one or more dots and/or dashes, perform the MORSE_CODE[…] lookup on that group.


            • (?<=[.-])( )(?=[.-]) — For any sequence of three spaces that is…




              • (?<=[.-]) — preceded by a dot or dash (a "positive lookbehind assertion"), and


              • (?=[.-]) — followed by a dot or dash (a "positive lookahead assertion")

              … then replace that group with a single space.




            •  * — Any other spaces should be replaced with nothing.

            It's unfortunate that the lookbehind and lookahead assertions are necessary, because the online test cases expect you to discard leading and trailing spaces. (An alternate technique you could use is to .strip() the input or the output.)






            share|improve this answer
























              up vote
              6
              down vote













              Since strings in Python are an immutable sequence type, building strings using += is not good practice, because it can lead to poor performance. Such concatenation may require the interpreter to allocate a new string and copy both the old and new parts into the new string (though CPython tries to avoid that when possible).



              I'd think of this as a string substitution exercise. String substitutions based on patterns can be done using regular expressions. The solution could be greatly simplified using re.sub():



              import re

              def decodeMorse(morse_code):
              return re.sub(
              '([.-]+)|(?<=[.-])( )(?=[.-])| *',
              lambda code: MORSE_CODE[code.group(1)] if code.group(1) else
              ' ' if code.group(2) else '',
              morse_code
              )


              The code above says:




              • ([.-]+) — For any sequence of one or more dots and/or dashes, perform the MORSE_CODE[…] lookup on that group.


              • (?<=[.-])( )(?=[.-]) — For any sequence of three spaces that is…




                • (?<=[.-]) — preceded by a dot or dash (a "positive lookbehind assertion"), and


                • (?=[.-]) — followed by a dot or dash (a "positive lookahead assertion")

                … then replace that group with a single space.




              •  * — Any other spaces should be replaced with nothing.

              It's unfortunate that the lookbehind and lookahead assertions are necessary, because the online test cases expect you to discard leading and trailing spaces. (An alternate technique you could use is to .strip() the input or the output.)






              share|improve this answer






















                up vote
                6
                down vote










                up vote
                6
                down vote









                Since strings in Python are an immutable sequence type, building strings using += is not good practice, because it can lead to poor performance. Such concatenation may require the interpreter to allocate a new string and copy both the old and new parts into the new string (though CPython tries to avoid that when possible).



                I'd think of this as a string substitution exercise. String substitutions based on patterns can be done using regular expressions. The solution could be greatly simplified using re.sub():



                import re

                def decodeMorse(morse_code):
                return re.sub(
                '([.-]+)|(?<=[.-])( )(?=[.-])| *',
                lambda code: MORSE_CODE[code.group(1)] if code.group(1) else
                ' ' if code.group(2) else '',
                morse_code
                )


                The code above says:




                • ([.-]+) — For any sequence of one or more dots and/or dashes, perform the MORSE_CODE[…] lookup on that group.


                • (?<=[.-])( )(?=[.-]) — For any sequence of three spaces that is…




                  • (?<=[.-]) — preceded by a dot or dash (a "positive lookbehind assertion"), and


                  • (?=[.-]) — followed by a dot or dash (a "positive lookahead assertion")

                  … then replace that group with a single space.




                •  * — Any other spaces should be replaced with nothing.

                It's unfortunate that the lookbehind and lookahead assertions are necessary, because the online test cases expect you to discard leading and trailing spaces. (An alternate technique you could use is to .strip() the input or the output.)






                share|improve this answer












                Since strings in Python are an immutable sequence type, building strings using += is not good practice, because it can lead to poor performance. Such concatenation may require the interpreter to allocate a new string and copy both the old and new parts into the new string (though CPython tries to avoid that when possible).



                I'd think of this as a string substitution exercise. String substitutions based on patterns can be done using regular expressions. The solution could be greatly simplified using re.sub():



                import re

                def decodeMorse(morse_code):
                return re.sub(
                '([.-]+)|(?<=[.-])( )(?=[.-])| *',
                lambda code: MORSE_CODE[code.group(1)] if code.group(1) else
                ' ' if code.group(2) else '',
                morse_code
                )


                The code above says:




                • ([.-]+) — For any sequence of one or more dots and/or dashes, perform the MORSE_CODE[…] lookup on that group.


                • (?<=[.-])( )(?=[.-]) — For any sequence of three spaces that is…




                  • (?<=[.-]) — preceded by a dot or dash (a "positive lookbehind assertion"), and


                  • (?=[.-]) — followed by a dot or dash (a "positive lookahead assertion")

                  … then replace that group with a single space.




                •  * — Any other spaces should be replaced with nothing.

                It's unfortunate that the lookbehind and lookahead assertions are necessary, because the online test cases expect you to discard leading and trailing spaces. (An alternate technique you could use is to .strip() the input or the output.)







                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Sep 2 at 3:59









                200_success

                124k14144401




                124k14144401



























                     

                    draft saved


                    draft discarded















































                     


                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function ()
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f202958%2fdecode-the-morse-code%23new-answer', 'question_page');

                    );

                    Post as a guest













































































                    這個網誌中的熱門文章

                    How to combine Bézier curves to a surface?

                    Carbon dioxide

                    Why am i infinitely getting the same tweet with the Twitter Search API?