3

I have a dictionary where the key is a letter in the alphabet and it’s value is its corresponding Morse code letter (e.g. ”A”: “.-“). I also have a user input where the user I puts there message. Once they press enter, it checks each input letter to see if it is in Morse code or an English letter by seeing if it is in the value or key. After that, I want it to then print its corresponding letter (e.g. if it found that “.-“, “A” would be printed). How would I do this?

Here is my code so far:

translation = {
"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": "--..",
" ": "  "
}

user_input = input("Input english or morse code message:\n").upper()

for i in user_input:
    if i in translation.keys(): 
        print(translation.values()) 
    if i in translation.values():
        print(translation.keys())
StrangeRanger
  • 299
  • 1
  • 2
  • 10
  • 1
    I tried copy pasting the code from the image into my terminal, but it didn't work. – cs95 May 05 '18 at 20:14
  • Does user input contains only values or key and values both? – Manoj Kumar Dhakad May 05 '18 at 20:19
  • It will probably not quite work how you want. It would be way easier to give a direction of translation, especially for the spaces. – MegaIng May 05 '18 at 20:20
  • 1
    A simple way to translate back from Morse to letters is to make another dictionary, with the Morse codes as the keys and the letters as the values. Do you understand how to build such a dict from your `translation` dict? – PM 2Ring May 05 '18 at 20:21
  • @ManojKumarDhakd I’m not totally sure what you mean by “does user input contains only values or keys and values both?”. The code does check to see if the user input matches anything in the dictionary values and keys, if that’s what you were meaning. – StrangeRanger May 05 '18 at 20:22
  • 1
    how are distinct letters separated in morse? `....` could be `H` or two `I` - unless you have separating spaces you can not 100% know if it is either – Patrick Artner May 05 '18 at 20:23
  • @PatrickArtner i see what you mean – StrangeRanger May 05 '18 at 20:27
  • You would have to split all combinations of a message in legths of 1 to 4 characters given, fit any character on it, limit those that can not fit and build some "probability" what the message would be - you get 30 maybe messages and need to take the "strongest" one ... – Patrick Artner May 05 '18 at 20:31

4 Answers4

2

For translating text to morse, just map the characters of the string to the corresponding value from the translation dictionary:

>>> msg = "HELLO WORLD"
>>> morse = ' '.join(map(translation.get, msg))
>>> morse
'.... . .-.. .-.. ---    .-- --- .-. .-.. -..'

Note that I separated the codes with spaces, otherwise it will be nearly impossible to decode the message back, as some sequences could yield in different combinations of characters. For the translation back, you first have to inverse the dictionary; then split the morse message by space and get the value from the inverse dictionary.

>>> trans_back = {v: k for k, v in translation.items()}
>>> ''.join(map(trans_back.get, morse.split()))
'HELLOWORLD'

Note that this removed the space, though. To fix this, you could use a different symbol than space to separate the morse code sequences. Or use this slightly more complicated version using re.split to split at a space, only if that space is not followed, or not preceded by another space:

>>> ''.join(map(trans_back.get, re.split("(?<! ) | (?! )", morse)))
'HELLO WORLD'

For deciding which way to translate, i.e. whether the original text is morse or plain-text, you could just check whether either the first, or all of the characters of the string are in the translation dictionary, or whether they are valid morse symbols:

if all(c in translation for c in msg):
    # translate to morse
elif all(c in ".- " for c in msg):
    # translate back
else:
    # don't know what to do

Note: This answer was posted before trailing spaces were added to all the entries in the dict.

tobias_k
  • 81,265
  • 12
  • 120
  • 179
  • Also, I don’t want the ability for Morse code to be turned to regular text to be dependent on the morse variable. How can I change the code for that? – StrangeRanger May 05 '18 at 21:43
  • @StrangeRanger What do you mean? `morse` is just the variable holding the previously translated text. In your case, that would probably just be `user_input`. I thought that would be self-explanatory... – tobias_k May 05 '18 at 22:15
  • I didn’t know if I needed to do something different for it to work. This is the error I get: “''.join(map(trans_back.get, user_input.split())); TypeError: sequence item 0: expected str instance, NoneType found” – StrangeRanger May 05 '18 at 22:23
  • @StrangeRanger Looks like what you entered is not valid morse code, or it is missing the separators. To check, replace the `''.join` with `list` to turn it into a list. The positions with `None` are the ones for which no translation could be found. If you want it to work even with those, you could try `“''.join((trans_back.get(x, "?") for x in user_input.split()))` to insert a `?` for every unknown character. – tobias_k May 06 '18 at 08:23
  • I figured it out. Here is the thread/question: https://stackoverflow.com/q/50196136/7945249 – StrangeRanger May 06 '18 at 18:41
  • I have one last question: how does the line `all(c in translation for c in msg)` and `all(c in “.- “ for c in msg)` work? Like what do each part do in combination with the others to complete its task? – StrangeRanger May 06 '18 at 18:46
  • @StrangeRanger Those use the `all` builtin function to check whether all the characters in the message are in the translation dict or in the string of valid morse code characters. If you don't know it, you should read up on `all` and other builtin functions. They are very handy. – tobias_k May 06 '18 at 22:10
  • @StrangeRanger So, the answer that helped you "figure it out" basically does the same as I did, it's just that you forgot to `split()` the input? – tobias_k May 06 '18 at 22:13
  • yes, I did forget the `split(' ')` with the `user_input` but I also needed `rsplit(' ')` at the end of the `v` in `trans_back`. I probably needed the `rsplit` because i added a space to the end of all the morse codes in the dictionary. – StrangeRanger May 06 '18 at 22:35
  • 1
    @StrangeRanger You only need `rstrip` because you added spaces to the end of each morse code. You can have the same effect by using `' '.join` instead of `''.join`, like I've shown in my answer. Next time you change your question in this way, you should drop a comment, as this will invalidate all the answers given so far. – tobias_k May 07 '18 at 08:04
  • would you recommend me changing my question back to where there was no space at the end of each Morse code? – StrangeRanger May 07 '18 at 15:18
  • @StrangeRanger Given that none of the other answers seems to have picked up those changes, I guess that would be the best. (But of course you should _not_ remove the spaces from your other question.) – tobias_k May 07 '18 at 16:06
  • I know I already asked this but could you explain/specify how `all(c in ".- " for c in msg):` works? Mainly how the `c in ".- "` part works. Because the line after that basically makes the letters and morse code change positions. Why can't you just use "translation" instead of ".- "? – StrangeRanger May 19 '18 at 19:48
  • @StrangeRanger In the first `if`, the `c in translations` checks whether `c` is a key in the dictionary. In other words, it's basically the same as `c in "ABCDE...XYZ "`, just a bit shorter. Likewise, `c in ".- "` checks whether `c` is one of the valid morse characters. We can't use `c in trans_back` here, as that would check whether each _individual_ character in the string is a valid multi-character morse code. (Well, in fact it _would_ work, as `"."` and `"-"` are both morse codes in their own right, but it would still feel wrong IMHO.) – tobias_k May 19 '18 at 20:07
  • So, instead of searching the keys, it looks at the values? – StrangeRanger May 19 '18 at 20:57
  • @StrangeRanger No, it does not use the dict at all. `c in ".- "` is the same, but shorter, as `c in [".", "-", " "]`, maybe it's clearer that way. It just checks whether either each character in the message is a normal letter, or a valid morse character. – tobias_k May 19 '18 at 21:22
  • Yea, that makes a little bit more sense. Thank you. – StrangeRanger May 19 '18 at 21:31
1

You are going to have to check if it is a Morse message or a 'alpha' message:

 # build a reversed dict
translation_from_morse = {v: k for k, v in translation.items()}

user_input = input("Input english or morse code message:\n").upper()

if user_input[0] in ".-":
    print(" ".join("".join(translation_from[morse] for morse in part.split(" ")) for part in user_input .split("  ")))
else:
    print(" ".join(translation_to.get(c, c) for c in user_input ))
MegaIng
  • 7,361
  • 1
  • 22
  • 35
0

Translating from a letter to morse code is quite simple in this case. You simply access the value using the key and concatenate each string value to another string. See below:

user_input = input("Input english to translate to morse code: ")

morse_code_message = ""
for i in user_input:
    if i in translation.keys():
         morse_code_message += translation[i]
print(morse_code_message)

However, dictionaries are not intended to be used the other way around. So morse to english will be different. You will have to search the dictionary values. See this post if you absolutely must do it this way. A cheap and easy way around this is to just make two translation tables and just use the same logic as is used for english to morse.

Kevin Welch
  • 1,488
  • 1
  • 9
  • 18
0

Build a reverse index of the original dict and then you have two convenient lookups. Now you have the problem that morse is a different length than characters. Assuming that the morse intercharacter gap is written as a space, you can consume the input stream one token at a time by first checking if its alpha (pop 1 char) or morse (pop multiple chars).

Note, do i in translation not translation.keys()

translation = {... your original dict ...}
morse_to_alpha = {v,k for k,v in translation.items()}

user_input = input("Input english or morse code message:\n").upper()

while user_input:
    if user_input[0] in translation:
        print(translation.pop(0))
    elif user_input[0] in '.-':
        try:
             separator = user_input.index(' ')
        except ValueError:
             separator = len(user_input)
        morse = user_input[:separator]
        del user_input[:separator+1]
        print(morse_to_alpha[morse])
    else:
        print("unkown symbol") 
tdelaney
  • 73,364
  • 6
  • 83
  • 116
  • This doesn't work. The morse codes have different lenghtd – MegaIng May 05 '18 at 20:27
  • morse is several characters = 1 aplha - you iterate the morse characterwise - wont work. you would have to keep adding to a temporary until you find one matching morse and then still you have ambiguity between `....` being a `H` or `II` and others as well, givong you a match thats not yet the "real" one, because that one would have been longer. – Patrick Artner May 05 '18 at 20:28