3
\$\begingroup\$

The Problem

Sam Morose served for many years as communications officer aboard the U.S.S. Dahdit, a U.S. Coast Guard frigate deployed in the South Pacific. Sam never quite got over the 1995 decision to abandon Morse code as the primary ship-to shore communication scheme, and was forced to retire soon after because of the undue mental anguish that it was causing. After leaving the Coast Guard, Sam landed a job at the local post office, and became a model U.S. Postal worker… That said, it isn’t surprising that Sam is now holding President Clinton hostage in a McDonald’s just outside the beltway. The FBI and Secret Service have been trying to bargain with Sam for the release of the president, but they find it very difficult since Sam refuses to communicate in anything other than Morse code. Janet Reno has just called you to write a program that will interpret Sam’s demands in Morse code as English. Morse code represents characters of an alphabet as sequences of dits (short key closures) and dahs (longer key closures). If we let a period (.) represent a dit and a dash (-) represent a dah, then the Morse code version of the English alphabet is:

morse table

Sample Input

Your program must takes its input from the ASCII text file morse.in. The file contains periods and dashes representing a message composed only of the English alphabet as specified above. One blank space is used to separate letters and three blanks are used to separate words. Sample contents of the file could appear as follows:

.... . .-.. .-.. ---   -- -.--   -. .- -- .   .. ...   ... .- --

Sample Output

Your program must direct its output to the screen and must be the English interpretation of the Morse code found in the input file. There must be no blanks between letters in the output and only one blank between words. You must use all capital letters in the output. The output corresponding to the input file above is:

HELLO MY NAME IS SAM

code.py

import re

codes = {
    '.-':'A',
    '-...':'B',
    '-.-.':'C',
    '-..':'D',
    '.':'E',
    '..-.':'F',
    '--.':'G',
    '....':'H',
    '..':'I',
    '.---':'J',
    '-.-':'K',
    '.-..':'L',
    '--':'M',
    '-.':'N',
    '---':'O',
    '...':'S',
    '-':'T',
    '..-':'U',
    '...-':'V',
    '.--':'W',
    '-..-':'X',
    '-.--':'Y',
    '--..':'Z'
}

with open('morse.in') as f:
    for line in f:
        t = []
        for s in line.strip().split(' '):
            t.append(codes.get(s) if s else ' ')
        print(re.sub(' +', ' ', ''.join(t)))

Any advice on performance enhancement and solution simplification is appreciated, as are topical comments!

\$\endgroup\$
  • \$\begingroup\$ I always wondered why jslint dislikes single quotes, now I know. \$\endgroup\$ – Felix Dombek Nov 6 '18 at 3:07
2
\$\begingroup\$

As long as you are using re.sub() to handle the spaces, you may as well use it to perform the entire task. Note that I've added entries to codes that maps triple-space to a space, and space to nothing. Also, since codes contains one entry per line, I prefer to put a comma after every entry, including a superfluous comma after the last one, to make it easy to add or remove entries.

import re

codes = {
    '.-': 'A',
    '-...': 'B',
    '-.-.': 'C',
    …
    '--..': 'Z',
    '   ': ' ',
    ' ': '',
}

with open('morse.in') as f:
    print(
        re.sub(
            '[.-]+|   | ',
            lambda match: codes[match.group()],
            f.read()
        ),
        end=''
    )
\$\endgroup\$
1
\$\begingroup\$

I realize this is just puzzle code, but treating this as a merge request for a production system:

  1. Replacing unknown codes with a space character seems counter to requirements. I would instead just t.append(codes[s]) and let the script exit with an error when given invalid input. If I wanted a more user friendly error message I'd catch this specific error and either print a warning on standard error before continuing or throw an application-specific error.
  2. You would also want to read from standard input rather than a specific file. That way you could use your script as part of a pipeline.
  3. Translation should be separate from reading input. That way the translation code can be reused independently of the input method.
  4. If you may have huge input I would use buffered reads rather than line-based. The former doesn't have to inspect every character, and the user can't kill the program by passing in a single long line.
  5. The mapping from a string of three spaces to a single space should be in codes. That way you're operating exactly to spec rather than second guessing what other sequences of spaces mean, and it gets rid of a costly regex replacement.
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.