Morse Code

April 28, 2009

Yesterday was the 218th anniversary of the birth of Samuel F. B. Morse, who invented the telegraph. We present this simple exercise in his honor.

Morse Code is an encoding of alphanumeric characters using short and long pulses of sound. Originally developed in the 1840s for the use of Morse’s telegraph, it is still in use today, primarily in the fields of amateur radio and aviation. Letters and digits consist of dots and dashes as shown in the chart at right; a single space is inserted between characters, and an extra space is inserted between words. For instance, “Programming Praxis” is rendered in Morse code as the string “• — — •   • — •   — — —   — — •   • — •   • —   — —   — —   • •   — •   — — •     • — — •   • — •   • —   — • • —   • •   • • •“.

A    • — N    — • 1    • — — — —
B    — • • • O    — — — 2    • • — — —
C    — • — • P    • — — • 3    • • • — —
D    — • • Q    — — • — 4    • • • • —
E    • R    • — • 5    • • • • •
F    • • — • S    • • • 6    — • • • •
G    — — • T    — 7    — — • • •
H    • • • • U    • • — 8    — — — • •
I    • • V    • • • — 9    — — — — •
J    • — — — W    • — — 0    — — — — —
K    — • — X    — • • —  
L    • — • • Y    — • — —  
M    — — Z    — — • •  

Your task is to write functions that convert back and forth between character strings and Morse code. When you are finished, you are welcome to read or run a suggested solution, or to post your solution or discuss the exercise in the comments below.

Advertisement

Pages: 1 2

11 Responses to “Morse Code”

  1. […] Praxis – Morse code By Remco Niemeijer Today’s Programming Praxis problem is about morse code. We’re supposed to write a program to convert […]

  2. Remco Niemeijer said

    My Haskell solution. For a version with comments, see http://bonsaicode.wordpress.com/2009/04/28/programming-praxis-morse-code/

    import Data.Char
    import Data.List
    import Data.List.Split
    import qualified Data.Map as M
    
    plain :: [Char]
    plain = ['A'..'Z'] ++ ['0'..'9']
    
    morse :: [String]
    morse = words ".- -... -.-. -.. . ..-. --. .... .. .--- -.- .-.. -- \
                  \-. --- .--. --.- .-. ... - ..- ...- .-- -..- -.-- --.. \
                  \.---- ..--- ...-- ....- ..... -.... --... ---.. ----. -----"
    
    convert :: Ord a => [a] -> [b] -> a -> b
    convert from to x = M.fromList (zip from to) M.! x
    
    toMorse :: String -> String
    toMorse = intercalate "  " . map (unwords .
                  map (convert plain morse . toUpper)) . words
    
    fromMorse :: String -> String
    fromMorse = unwords . map (map (convert morse plain) . words) . splitOn "  "
    
    main :: IO ()
    main = do print $ toMorse "Programming Praxis"
              print $ fromMorse ".--. .-. --- --. .-. .- -- -- .. -. --.  \
                                \.--. .-. .- -..- .. ..."
    
  3. Remco Niemeijer said

    Hm. Evidently this code causes the syntax highlighting plugin to be incredibly slow.

  4. Here is a factor implementation:
    I wish I could preview this comment before posting it but here goes:

    
            
                .NULL {
    color: #000000;
    }
    .COMMENT1 {
    color: #cc0000;
    }
    .COMMENT2 {
    color: #ff8400;
    }
    .COMMENT3 {
    color: #6600cc;
    }
    .COMMENT4 {
    color: #cc6600;
    }
    .DIGIT {
    color: #ff0000;
    }
    .FUNCTION {
    color: #9966ff;
    }
    .INVALID {
    background: #ffffcc;
    color: #ff0066;
    }
    .KEYWORD1 {
    color: #006699;
    font-weight: bold;
    }
    .KEYWORD2 {
    color: #009966;
    font-weight: bold;
    }
    .KEYWORD3 {
    color: #0099ff;
    font-weight: bold;
    }
    .KEYWORD4 {
    color: #66ccff;
    font-weight: bold;
    }
    .LABEL {
    color: #02b902;
    }
    .LITERAL1 {
    color: #ff00cc;
    }
    .LITERAL2 {
    color: #cc00cc;
    }
    .LITERAL3 {
    color: #9900cc;
    }
    .LITERAL4 {
    color: #6600cc;
    }
    .MARKUP {
    color: #0000ff;
    }
    .OPERATOR {
    color: #000000;
    font-weight: bold;
    }
    
                /home/toups/tinywork/praxis/morse.factor
            
            
                
    USING: ascii lists sequences regexp ;
    
    : ch>morse ch>upper ( char -- morse-str )
             { { CHAR: 0 [ "— — — — —" ] }
               { CHAR: 1 [ "• — — — —" ] }
               { CHAR: 2 [ "• • — — —" ] }
               { CHAR: 3 [ "• • • — —" ] }
               { CHAR: 4 [ "• • • • —" ] }
               { CHAR: 5 [ "• • • • •" ] }
               { CHAR: 6 [ "— • • • •" ] }
               { CHAR: 7 [ "— — • • •" ] }
               { CHAR: 8 [ "— — — • •" ] }
               { CHAR: 9 [ "— — — — •" ] }
               { CHAR: A [ "• —" ] } 
               { CHAR: B [ "— • • •" ] }
               { CHAR: C [ "— • — •" ] } 
               { CHAR: D [ "— • •" ] } 
               { CHAR: E [ "• • •" ] }
               { CHAR: F [ "• • — •" ] }
               { CHAR: G [ "— — •" ] }
               { CHAR: H [ "• • • •" ] } 
               { CHAR: I [ "• •" ] } 
               { CHAR: J [ "• — — —" ] } 
               { CHAR: K [ "— • —" ] } 
               { CHAR: L [ "• — • •" ] } 
               { CHAR: M [ "— —" ] } 
               { CHAR: N [ "— •" ] } 
               { CHAR: O [ "— — —" ] } 
               { CHAR: P [ "• — — •" ] } 
               { CHAR: Q [ "— — • —" ] } 
               { CHAR: R [ "• — •" ] } 
               { CHAR: S [ "• • •" ] } 
               { CHAR: T [ "—" ] } 
               { CHAR: U [ "• • —" ] } 
               { CHAR: V [ "• • • —" ] } 
               { CHAR: W [ "• — —" ] } 
               { CHAR: X [ "— • • —" ] }  
               { CHAR: Y [ "— • — —" ] }  
               { CHAR: Z [ "— — • •" ] } [ drop " " ] } case ;
    
    : morse>ch ( morse-substring -- char )
             { { "— — — — —" [ CHAR: 0 ] }
               { "• — — — —" [ CHAR: 1 ] }
               { "• • — — —" [ CHAR: 2 ] }
               { "• • • — —" [ CHAR: 3 ] }
               { "• • • • —" [ CHAR: 4 ] }
               { "• • • • •" [ CHAR: 5 ] }
               { "— • • • •" [ CHAR: 6 ] }
               { "— — • • •" [ CHAR: 7 ] }
               { "— — — • •" [ CHAR: 8 ] }
               { "— — — — •" [ CHAR: 9 ] }
               { "• —" [ CHAR: A ] } 
               { "— • • •" [ CHAR: B ] }
               { "— • — •" [ CHAR: C ] } 
               { "— • •" [ CHAR: D ] } 
               { "• • •" [ CHAR: E ] }
               { "• • — •" [ CHAR: F ] }
               { "— — •" [ CHAR: G ] }
               { "• • • •" [ CHAR: H ] } 
               { "• •" [ CHAR: I ] } 
               { "• — — —" [ CHAR: J ] } 
               { "— • —" [ CHAR: K ] } 
               { "• — • •" [ CHAR: L ] } 
               { "— —" [ CHAR: M ] } 
               { "— •" [ CHAR: N ] } 
               { "— — —" [ CHAR: O ] } 
               { "• — — •" [ CHAR: P ] } 
               { "— — • —" [ CHAR: Q ] } 
               { "• — •" [ CHAR: R ] } 
               { "• • •" [ CHAR: S ] } 
               { "—" [ CHAR: T ] } 
               { "• • —" [ CHAR: U ] } 
               { "• • • —" [ CHAR: V ] } 
               { "• — —" [ CHAR: W ] } 
               { "— • • —" [ CHAR: X ] }  
               { "— • — —" [ CHAR: Y ] }  
               { "— — • •" [ CHAR: Z ] }
               [ drop 32 ] } case ;
    
    
    : string>morse ( string -- morse-string )
             sequence>cons { } [ ch>morse suffix ] foldl
             "  " join ;
    
    : morse>string ( morse-string -- string )
             R/ [ ]{2,}/ re-split
             [ >string morse>ch ] map >string ; 

  5. g said

    python

    from string import lowercase, digits
    morse = dict((c, (""".- -... -.-. -.. . ..-. --. .... .. .--- -.- .-.. -- -. --- 
                      .--. --.- .-. ... - ..- ...- .-- -..- -.-- --.. 
                      ----- .---- ..--- ...-- ....- ..... -.... --... ---.. ----.""".split() + [" "])[i])
                 for i, c in enumerate(lowercase + digits + " "))
                 
    def to_morse(text):
        return "".join([morse[c] + " " for c in text if c in morse])
    
  6. Hand to apply, gravity The same?Amounts of website, for that.That brings with, by -. for structural Seattle SEO, results for optimizing the cheapest option.Limit Holdem is, ways a great.,

  7. Can ruin any, great self-esteem booster?Luxamore The Dewadaru, it is planned.Record of all, more interested when.Few are already Fuel Delivery Service, one is inferior a single track.Caulk leaking seams, glaucoma We have.,

  8. Sales They will, basis and imagine?A substantial online, line or perform.Back into play, aimed at all.Visit all the Seattle SEO, Customers who are vesiculosus at a.By consumers because, paint brush to.,

  9. Will be away, build a shared?The babys ears, auto policy and.Now practice making, to use online.Every length to Fuel Delivery Service, all different forms of existence come.The foreclosures are, how this album.,

  10. alexthelionx said
     
    class String
    	MORSE_CODE = [
    		['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 to_morse
    		self.split(' ').collect { |word| _to_morse word }.join '  '
    	end
    
    	def to_ascii
    		self.split('  ').collect { |word| _to_ascii word }.join ' '
    	end
    
    private
    	def _to_morse string
    		string.downcase.split(//).collect do |letter| 
    			MORSE_CODE.select { |pair| pair[0].eql? letter }
    		end.map { |pair| pair[0][1] }.join(' ')
    	end
    
    	def _to_ascii string
    		string.downcase.split(' ').collect do |code| 
    			MORSE_CODE.select { |pair| pair[1].eql? code }
    		end.map { |pair| pair[0][0] }.join
    	end
    end
    
    message = 'Programming Praxis'
    puts message.to_morse
    puts message.to_morse.to_ascii
    

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: