Pistrie
How do I check whether a string only consists of characters that are keys inside a map?
I’m creating a piece of code that translates a string into Morse code, but I need to check whether the string can be translated into Morse code at all. I’ve got a map that has all the translations, so I figured the most optimal way would be to check whether all the characters in the string appear in this map. Would it somehow be possible to turn this into a regex so I can simply use String.match?/2?
@morse_dict %{
"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" => "--..",
"0" => "-----",
"1" => ".----",
"2" => "..---",
"3" => "...--",
"4" => "....-",
"5" => ".....",
"6" => "-....",
"7" => "--...",
"8" => "---..",
"9" => "----.",
"." => ".-.-.-",
"," => "--..--",
"?" => "..--..",
"'" => ".----.",
"!" => "-.-.--",
"/" => "-..-.",
"(" => "-.--.",
")" => "-.--.-",
"&" => ".-...",
":" => "---...",
";" => "-.-.-.",
"=" => "-...-",
"+" => ".-.-.",
"-" => "-....-",
"_" => "..--.-",
"\"" => ".-..-.",
"$" => "...-..-",
"@" => ".--.-.",
" " => "/"
}
Thanks ![]()
Marked As Solved
JohnnyCurran
You can do it in 3 lines. Split, map, then join
defmodule MorseCode do
@morse_dict %{
"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" => "--..",
"0" => "-----",
"1" => ".----",
"2" => "..---",
"3" => "...--",
"4" => "....-",
"5" => ".....",
"6" => "-....",
"7" => "--...",
"8" => "---..",
"9" => "----.",
"." => ".-.-.-",
"," => "--..--",
"?" => "..--..",
"'" => ".----.",
"!" => "-.-.--",
"/" => "-..-.",
"(" => "-.--.",
")" => "-.--.-",
"&" => ".-...",
":" => "---...",
";" => "-.-.-.",
"=" => "-...-",
"+" => ".-.-.",
"-" => "-....-",
"_" => "..--.-",
"\"" => ".-..-.",
"$" => "...-..-",
"@" => ".--.-.",
" " => "/"
}
def translate(string) when is_binary(string) do
characters = String.split(string, "", trim: true)
maybe_morse = for c <- characters, do: @morse_dict[c]
if Enum.all?(maybe_morse), do: IO.puts(Enum.join(maybe_morse)), else: IO.puts("Could not translate #{string} to morse code")
end
end
MorseCode.translate("THIS IS VALID MORSE CODE")
MorseCode.translate("THIS IS <INVALID> MORSE CODE")
Outputs:
-........./...../...-.-.-....-../-----.-...../-.-.----...
Could not translate THIS IS <INVALID> MORSE CODE to morse code
Also Liked
adamu
I’m not sure if there’s a way to create the regex automatically, but here’s a handwritten one. This is faster than all the versions I could think of (including JonnyCurran’s above) that actually translate the message:
def valid?(str), do: str =~ ~r/^[\w.,?'!\/()&:;=+_\\$@ -]+$/
Here’s a version that does it by generating function clauses from the map at compile-time, and uses binary pattern matching, which is faster than the regex:
for char <- Map.keys(@morse_dict) do
defp valid_char?(unquote(char)), do: true
end
defp valid_char?(_), do: false
def valid?(<<char::binary-1>>), do: valid_char?(char)
def valid?(<<char::binary-1, rest::binary>>), do: valid_char?(char) and valid?(rest)







