Alex
Alex

Reputation: 109

Convert string through hash

I'm trying to convert a string of morse code into words. I split the string into words. Then I split each word into a secondary array of letters and numbers.

 def self.decode(str)
    decoded = ""
    arr = []
    p arr = str.split('  ')
    p arr.map! { |i| i.split('  ') }

    arr.each do |r|
      r.each do |i|
          decoded += @morse.invert[i].to_s[-1]
      end
    end

    p decoded
end

In my hash, I use numbers. They start with N. In to_s[-1], the -1 is to drop the N.

I get this error:

`+': no implicit conversion of nil into String

I can figure out how to get past it though because I don't see a nil value in the array.

class Morse

    @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: '--..',
        ' ': ' ' ,
        N1: '.----',
        N2: '..---',
        N3: '...--',
        N4: '....-',
        N5: '.....',
        N6: '-....',
        N7: '--...',
        N8: '---..',
        N9: '----.',
        N0: '-----'
    }

def self.encode(str)
    encoded = ""
    sym_temp = ""
    str = str.upcase!
    str.each_char do |c|
        ascii_check = c.ord
        if ascii_check.between?(65,90)
            temp = str[c].to_sym
            encoded += "#{@morse[temp]}" + " "
        elsif ascii_check.between?(48,57)   
            temp = "N".concat(str[c]).to_sym
            encoded += "#{@morse[temp]}" + " "
        elsif ascii_check ===(32)
            temp = str[c].to_sym
            encoded += "#{@morse[temp]}"
        end
    end
    p encoded
end

def self.decode(str)
    decoded = ""
    arr = []
    # str.split('  ').map do |i|
    p arr = str.split('  ')
    p arr.map! { |i| i.split('  ') }

    arr.each do |r|
      r.each do |i|
        p  decoded += @morse.invert[i].to_s[-1].to_s
      end
    end             

    p decoded
end

# def self.read_file
    # # @Temp = File.read("preamble_encode.txt").chomp
      # # File.open('hiscore.txt'){|f| f.lines.map{|l| l.chomp!.split(',')}}
    # # @Temp = File.foreach("preamble_encode.txt", 'r') {|f| f.lines.map{|l| l.chomp}}

# end

# def self.write_file
    # # Temp2 = File.open('preamble_decode.txt', 'w') do |f|
        # # f.puts Temp2
    # # end
# end

end


test = "Abc 1oL!"
test2 = ".-- .  - .... .  .--. . --- .--. .-.. ."
Morse.encode(test)
Morse.decode(test2)

Upvotes: 1

Views: 324

Answers (2)

Cary Swoveland
Cary Swoveland

Reputation: 110665

As you question has been answered, I would like to suggest how you may write methods for coding and decoding.

Firstly, the keys of your hash should be strings rather than symbols, as the hash is being used to code strings, which are made up of single-character strings. We also need the digits to be, '0' to '9' rather than 'N0' to 'N9'. Spaces are represented by time delays equal to seven dots, rather than combinations of dots and dashes, so I've represented spaces by the string '<delay>'. See the Morse Wiki.

Since the hash won't change, I've made it a constant rather than the value of an instance variable.

CharactersToMorse = {
  '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' => '--..' , ' ' => '<delay>', '0' => '-----', '1' => '.----',
  '2' => '..---', '3' => '...--', '4' => '....-', '5' => '.....', '6' => '-....',
  '7' => '--...', '8' => '---..', '9' => '----.'
}

We will need to decode, so I'll assign the inverted hash to a constant as well.

MorseToCharacters = CharactersToMorse.invert
  #=> {".-"=>"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", "<delay>"=>" ", "-----"=>"0", ".----"=>"1", "..---"=>"2",
  #    "...--"=>"3", "....-"=>"4", "....."=>"5", "-...."=>"6", "--..."=>"7",
  #    "---.."=>"8", "----."=>"9"} 

Our methods for coding and decoding are now very simple.

def code(text)
  text.each_char.map { |c| CharactersToMorse[c] }
end

def decode(morse)
  morse.map { |m| MorseToCharacters[m] }.join(' ')
end

Let's try it.

text = "NOW IS THE TIME FOR 47 RUBIESTS TO COME TO THE AID OF THEIR BOWLING TEAM"

morse = code(text)
  #=> ["-.", "---", ".--", "<delay>", "..", "...", "<delay>", "-", "....",
  #    ".", "<delay>", "-", "..", "--", ".", "<delay>", "..-.", "---", ".-.",
  #    "<delay>", "....-", "--...", "<delay>", ".-.", "..-", "-...", "..",
  #    ".", "...", "-", "...", "<delay>", "-", "---", "<delay>", "-.-.", "---",
  #    "--", ".", "<delay>", "-", "---", "<delay>", "-", "....", ".", "<delay>",
  #    ".-", "..", "-..", "<delay>", "---", "..-.", "<delay>", "-", "....",
  #    ".", "..", ".-.", "<delay>", "-...", "---", ".--", ".-..", "..", "-.",
  #    "--.", "<delay>", "-", ".", ".-", "--"] 

decode(morse)
  #=> "NOW IS THE TIME FOR 47 RUBIESTS TO COME TO THE AID OF THEIR BOWLING TEAM"

If for some reason the keys of CharactersToMorse must be symbols, change the methods to:

def code(text)
  text.each_char.map { |c| CharactersToMorse[c.to_sym] }
end

def decode(morse)
  morse.map { |m| MorseToCharacters[m].to_s }.join(' ')
end

Upvotes: 3

Some Guy
Some Guy

Reputation: 1511

Your problem is here:

        :P => :'.--.',

Your colon on the right hand side of the hash rocket is making that a symbol, not a string. As it happens, your test case for decode includes a P. When you try to look up the String '.--.', it doesn't find it and returns nil.

Upvotes: 5

Related Questions