Morse Decoder

On the morse Decoder project, I keep receiving an error that I’m not sure how to fix. Can anyone shed some light on this for me?


var englishText = "this is a secret message"

var secretMessage = ".... --- .-- -.. -.--   .--. .- .-. - -. . .-."

// Add your code below 🤫
var letterToMorse = [
  "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": "--.."
]
var morseText = ""
for element in englishText {
  if let morseChar = letterToMorse["\(element)"] {
 morseText += morseChar + " "
  }
  else {
    morseText += "   "
  }
}
print(morseText)
var decodedMessage = ""
var morseCodeArray = ""
var currMorse = ""
for char in secretMessage {
if char != " " {
currMorse.append(char)
}
else {
  switch currMorse {
case "":
 currMorse += " "
case " ": 
morseCodeArray.append(" ")
currMorse = ""
default:
morseCodeArray.append(currMorse)
currMorse = ""
  }
}
}
print(morseCodeArray)
var morseToLetter: [String: String] = [:]
for (letter, morseChar) in letterToMorse {
  morseToLetter[morseChar]=letter
}
for morseValue in morseCodeArray{
  if let letterChar = morseToLetter[morseValue]{
    decodedMessage += letterChar
  }
  else {
  decodedMessage += " "
  }
}
print(decodedMessage)

This is the error I receive…


Morse.swift:70:36: error: cannot subscript a value of type '[String : String]' with an argument of type 'String.Element' (aka 'Character')
  if let letterChar = morseToLetter[morseValue]{
                      ~~~~~~~~~~~~~^~~~~~~~~~~~
Swift.Dictionary<τ_0_0, τ_0_1>:2:23: note: found this candidate
    @inlinable public subscript(key: Key) -> Value? { get set }

Morse Decoder

Swift is doesn’t have straightforward subscript access of nth index in a string. You might want to check these discussions:

https://developer.apple.com/documentation/swift/string/1540052-subscript

Off topic

This inspired a port to Python. Lots of fun (for the hour or so it took).

def invert_dict(d):
    f = {}
    for k, v in d.items():
        f[v] = k
    return f

englishText = "this is a secret message"
secretMessage = ".... --- .-- -.. -.--   .--. .- .-. - -. . .-."
letterToMorse
letterToMorse = {
  "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": "--.."
}
morseToLetter = invert_dict(letterToMorse)
morseText = ""
letterText = ""
for char in englishText:
  morseChar = letterToMorse.get(char, " ")
  morseText += morseChar + " "
print(morseText)
for code in morseText.replace('  ', ' %').split():
    letterChar = morseToLetter.get(code, ' ')
    letterText += letterChar
print(letterText)

I’ve tried to implement as close to the same logic as what I could discern from a language I do not know or use. Cool stuff! BTW, notice there is no bloated logic, only an inverted object. Two simple helper functions and conversion either way is a snap.

The secret message will be resolved whence these procedures are abstracted to functions.

def encode(text):
    code = ''
    for letter in text:
        morse = letterToMorse.get(letter, ' ')
        code += morse + ' '
    return code
def decode(code):
    text = ''
    for morse in code.replace('  ', ' %').split():
        letter = morseToLetter.get(morse, ' ')
        text += letter
    return text

print (decode(secret_message))

Don’t want to spoil it, so you’ll have to run this code in Python, or port it to Swift.

Is it spoiling it that we have introduced another language?

No, just trying to make sense of it all, still fairly new to all this.

1 Like

In the above Python code, .get() is a method of the dict class. Swift calls them dictionaries, as well, though it looks like bracket syntax rather than braces. From what I can find, .objectForKey("AAPL") is a similar method though one would have to read up more to see if a default return value can be assigned like the get method above. Not sure how a variable would be used but that should come up in the reading, as well.

The .replace() method is from the str class, as is the .split() method which defaults to splitting on space characters. It returns a list (an array of sorts). The Morse code is represented with one space between letters and two spaces between words. I substituted ' %' so that after splitting, the % would be left behind to break up the words. .get() does not find the character in the dictionary so supplies a space character in its place. The method is convenient and useful since it eliminates any if…else logic.

If I knew Swift, I would port that back for you, but it should be a fun exercise for you as you gain more familiarity with that language. I’m a Windows user so have no need to learn Swift (who does at 67?)

1 Like

I figured it out, I needed to use String Interpolation to get the string subscript to match the data type.

for morseValue in morseCodeArray{
if let letterChar = morseToLetter["\(morseValue)"] {
    decodedMessage += letterChar
  }
  else {
  decodedMessage += " "
  }
}
print(decodedMessage)

1 Like

Out of interest, have you written a dictionary inverter, yet? Or is too early to be talking about methods (functions)?

Still off topic, here is a running version of the Python code above…

https://www.codecademy.com/workspaces/622da3f6e4b7f30c4529af72

1 Like

a bit early haha, I’ve only used it in swift playgrounds.

1 Like