Reputation: 65
I am very new to programming in Erlang. I am making a program to decode braille but I am having a problem trying to split a string every 2 characters with the absence of a delimiter, and putting them into a list.
First I read in the braille alphabet like this:
inKey(Key1) -> Key1.
inKey2(Key2) -> Key2.
inKey3(Key3) -> Key3.
Key 1-3 are strings and look like this:"x.x.xxxxx.xxxxx..x.xx.x.xxxxx.xxxxx..x.xx.x..xxxxxx."
these 3 keys form the braille information that I will later use to transform braille into normal characters.
Now I need to split this string and place them in a list so that it would look like this: ["x.","x.","xx","xx",x.","xx","xx","x.",".x
and so on.
If the string is split I want to insert them into my coding list like shown in Tuplet for the character A
Code=[#row{name="R1",alfabet=[#codes{letter="A",braille="X."},#codes{letter="B",braille=""}
Can someone helpe me out?
`
Upvotes: 3
Views: 989
Reputation: 14042
It is late to post this, nevertheless I do it because I think that the type of variable you want to use to store the alphabet is not really appropriate to the different usages you may have. I wrote a small code to show the usage of two maps (one for decoding, one for encoding). Sorry there are only a few comments in the code.
-module (braille).
-export ([test/1,show_maps/0]).
test(Str) ->
% build the conversion map
{Alphabet,Braille} = init(),
% transform a string into braille and print it
Lines = print_braille(Str,Alphabet),
% transform the braille result into string , check the result and print it
Str = read_braille(Lines,Braille),
ok.
show_maps() ->
{Alphabet,Braille} =init(),
io:format("Alphabet = ~n~100p~n~nBraille = ~n~100p~n",[Alphabet,Braille]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% creates one map to allow the conversion from latin letter to braille: Alphabet
% and one map to allow the conversion from braille to latin : Braille
% This should be the init function of a conversion server, in charge to maintain the conversion maps
init() ->
L1="x.x.xxxxx.xxxxx..x.xx.x.xxxxx.xxxxx..x.xx.x..xxxxxx.",
L2="..x....x.xx.xxxxx.xx..x....x.xx.xxxxx.xx..x.xx...x.x",
L3="....................x.x.x.x.x.x.x.x.x.x.xxxx.xxxxxxx",
LL1 = split_str(L1),
LL2 = split_str(L2),
LL3 = split_str(L3),
Alphabet = init_alphabet(LL1,LL2,LL3,$a,#{$ => #{1 => "..", 2 => "..", 3=> ".."}}),
Braille = init_braille(Alphabet),
{Alphabet,Braille}.
% a tail recursive function to split the input string into packets of 2 characters
split_str_tail_recursive([],R) ->
lists:reverse(R);
split_str_tail_recursive([A,B|Rest],R) ->
split_str_tail_recursive(Rest,[[A,B]|R]).
% interface to call the recursive fuction
split_str(L) -> split_str_tail_recursive(L,[]).
init_alphabet([],[],[],_,R) ->
R;
init_alphabet([H1|T1],[H2|T2],[H3|T3],C,R) ->
init_alphabet(T1,T2,T3,C+1,maps:put(C,#{1 => H1, 2 => H2, 3=> H3},R)).
init_braille(Alphabet) ->
H = fun(K,V,AccIn) -> maps:put({maps:get(1,V),maps:get(2,V),maps:get(3,V)},K,AccIn) end,
maps:fold(H,#{},Alphabet).
%transform a latin lower cap string into 3 lines representing a braille output, print them and returns the 3 lines
print_braille(S,Alphabet) ->
Line1 = lists:flatmap(fun(C) -> maps:get(1,maps:get(C,Alphabet)) end,S),
Line2 = lists:flatmap(fun(C) -> maps:get(2,maps:get(C,Alphabet)) end,S),
Line3 = lists:flatmap(fun(C) -> maps:get(3,maps:get(C,Alphabet)) end,S),
io:format("~s~n~s~n~s~n",[Line1,Line2,Line3]),
{Line1,Line2,Line3}.
% transform a tuple of 3 lines braille representation into latin string, print it and return it
read_braille({Line1,Line2,Line3},Braille) ->
List = lists:zip3(split_str(Line1),split_str(Line2),split_str(Line3)),
Str = lists:map(fun(B) -> maps:get(B,Braille) end,List),
io:format("~s~n", [Str]),
Str.
and here the usage:
1> c(braille).
{ok,braille}
2> braille:show_maps().
Alphabet =
#{32 => #{1 => "..",2 => "..",3 => ".."},
97 => #{1 => "x.",2 => "..",3 => ".."},
98 => #{1 => "x.",2 => "x.",3 => ".."},
99 => #{1 => "xx",2 => "..",3 => ".."},
100 => #{1 => "xx",2 => ".x",3 => ".."},
101 => #{1 => "x.",2 => ".x",3 => ".."},
102 => #{1 => "xx",2 => "x.",3 => ".."},
103 => #{1 => "xx",2 => "xx",3 => ".."},
104 => #{1 => "x.",2 => "xx",3 => ".."},
105 => #{1 => ".x",2 => "x.",3 => ".."},
106 => #{1 => ".x",2 => "xx",3 => ".."},
107 => #{1 => "x.",2 => "..",3 => "x."},
108 => #{1 => "x.",2 => "x.",3 => "x."},
109 => #{1 => "xx",2 => "..",3 => "x."},
110 => #{1 => "xx",2 => ".x",3 => "x."},
111 => #{1 => "x.",2 => ".x",3 => "x."},
112 => #{1 => "xx",2 => "x.",3 => "x."},
113 => #{1 => "xx",2 => "xx",3 => "x."},
114 => #{1 => "x.",2 => "xx",3 => "x."},
115 => #{1 => ".x",2 => "x.",3 => "x."},
116 => #{1 => ".x",2 => "xx",3 => "x."},
117 => #{1 => "x.",2 => "..",3 => "xx"},
118 => #{1 => "x.",2 => "x.",3 => "xx"},
119 => #{1 => ".x",2 => "xx",3 => ".x"},
120 => #{1 => "xx",2 => "..",3 => "xx"},
121 => #{1 => "xx",2 => ".x",3 => "xx"},
122 => #{1 => "x.",2 => ".x",3 => "xx"}}
Braille =
#{{"..","..",".."} => 32,
{".x","x.",".."} => 105,
{".x","x.","x."} => 115,
{".x","xx",".."} => 106,
{".x","xx",".x"} => 119,
{".x","xx","x."} => 116,
{"x.","..",".."} => 97,
{"x.","..","x."} => 107,
{"x.","..","xx"} => 117,
{"x.",".x",".."} => 101,
{"x.",".x","x."} => 111,
{"x.",".x","xx"} => 122,
{"x.","x.",".."} => 98,
{"x.","x.","x."} => 108,
{"x.","x.","xx"} => 118,
{"x.","xx",".."} => 104,
{"x.","xx","x."} => 114,
{"xx","..",".."} => 99,
{"xx","..","x."} => 109,
{"xx","..","xx"} => 120,
{"xx",".x",".."} => 100,
{"xx",".x","x."} => 110,
{"xx",".x","xx"} => 121,
{"xx","x.",".."} => 102,
{"xx","x.","x."} => 112,
{"xx","xx",".."} => 103,
{"xx","xx","x."} => 113}
ok
3> braille:test("the quick brown fox jumps over the lazy dog").
.xx.x...xxx..xxxx...x.x.x..xxx..xxx.xx...xx.xxxx.x..x.x.x.x....xx.x...x.x.x.xx..xxx.xx
xxxx.x..xx..x.......x.xx.xxx.x..x..x....xx....x.x....xx..xxx..xxxx.x..x....x.x...x.xxx
x.......x.xx....x.....x.x..xx.....x.xx....xxx.x.x...x.xx..x...x.......x...xxxx....x...
the quick brown fox jumps over the lazy dog
ok
4>
Upvotes: 2
Reputation: 48599
In Erlang, you need to remember that a string is equivalent to a list of numbers, where the numbers are the ascii codes for each character. The confusing thing is that sometimes the shell displays a list of numbers as a string, and sometimes it displays a list of numbers as a list of numbers. That is a TERRIBLE feature of the erlang shell.
Despite what the shell displays, just remember that a string is a list of numbers. The problem then becomes, what if you want to output a list of numbers and not a string? The answer is: you can't do anything about that; the shell may display your list of numbers as a string...unless you take further action:
45> Grades = [97,98,99].
"abc"
Wtf??!
46> io:format("~w~n", [Grades]).
[97,98,99]
ok
Another way of thinking about it is this: the erlang string syntax "abc"
is just a shortcut for creating the list of numbers [97,98,99]
.
Next, you can deconstruct a list with a pattern like this:
[Head|Tail] = [1,2,3]
In the shell:
8> [Head|Tail] = [1, 2, 3, 4].
[1,2,3,4]
9> Head.
1
10> Tail.
[2,3,4]
But, the cons operator |
is more flexible than that, and it allows you to do this:
13> [N1,N2 | T] = [1, 2, 3, 4].
[1,2,3,4]
14> N1.
1
15> N2.
2
16> T.
[3,4]
Therefore, you can do this:
-module(my).
-compile(export_all).
string() ->
"x.x.xxxxx.xxxxx..x.xx.x.xxxxx.xxxxx..x.xx.x..xxxxxx.".
chunk2([]) -> [];
chunk2([N1, N2| Tail]) ->
[[N1,N2] | chunk2(Tail) ].
In the shell:
2> c(my).
my.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,my}
3> my:chunk2(my:string()).
["x.","x.","xx","xx","x.","xx","xx","x.",".x",".x","x.",
"x.","xx","xx","x.","xx","xx","x.",".x",".x","x.","x.",".x",
"xx","xx","x."]
4>
Finally, to construct a list of #code{}
records, you can do this:
-module(my).
-compile(export_all).
-record(codes, {letter, braille}).
string() ->
"x.x.xxxxx.xxxxx..x.xx.x.xxxxx.xxxxx..x.xx.x..xxxxxx.".
chunk2([]) -> [];
chunk2([N1, N2| Tail]) ->
[[N1,N2] | chunk2(Tail) ].
make_record_list(Letters, Chunks) ->
lists:zipwith(
fun(Letter, Chunk) -> #codes{letter=[Letter], braille=Chunk} end,
Letters,
Chunks
).
In the shell:
31> c(my).
my.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,my}
32> ListOfCapLetters = lists:seq($A, $Z).
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
33> BrailleChunks = my:chunk2(my:string()).
["x.","x.","xx","xx","x.","xx","xx","x.",".x",".x","x.",
"x.","xx","xx","x.","xx","xx","x.",".x",".x","x.","x.",".x",
"xx","xx","x."]
34> Records = my:make_record_list(ListOfCapLetters, BrailleChunks).
[{codes,"A","x."},
{codes,"B","x."},
{codes,"C","xx"},
{codes,"D","xx"},
{codes,"E","x."},
{codes,"F","xx"},
{codes,"G","xx"},
{codes,"H","x."},
{codes,"I",".x"},
{codes,"J",".x"},
{codes,"K","x."},
{codes,"L","x."},
{codes,"M","xx"},
{codes,"N","xx"},
{codes,"O","x."},
{codes,"P","xx"},
{codes,"Q","xx"},
{codes,"R","x."},
{codes,"S",".x"},
{codes,"T",".x"},
{codes,"U","x."},
{codes,"V","x."},
{codes,"W",".x"},
{codes,"X","xx"},
{codes,"Y","xx"},
{codes,"Z",[...]}]
It looks like there may be a problem with the last record, so let's check:
37> tl(Records).
[{codes,"B","x."},
{codes,"C","xx"},
{codes,"D","xx"},
{codes,"E","x."},
{codes,"F","xx"},
{codes,"G","xx"},
{codes,"H","x."},
{codes,"I",".x"},
{codes,"J",".x"},
{codes,"K","x."},
{codes,"L","x."},
{codes,"M","xx"},
{codes,"N","xx"},
{codes,"O","x."},
{codes,"P","xx"},
{codes,"Q","xx"},
{codes,"R","x."},
{codes,"S",".x"},
{codes,"T",".x"},
{codes,"U","x."},
{codes,"V","x."},
{codes,"W",".x"},
{codes,"X","xx"},
{codes,"Y","xx"},
{codes,"Z","x."}]
Nope, the first output just reached the limit of what the shell was willing to display.
Note that each element of ListOfCapLetters is a number, and a number is not a list, so each element of ListOfCapLetters is not a string itself. To create a string from a number, you need to put it inside a list, hence [Letter]
. It's the same difference between: String = [97,98,99]
and ListOfStrings = [[97], [98], [99]]
:
40> String = [97,98,99].
"abc"
41> hd(String).
97
42> ListOfStrings = [[97], [98], [99]].
["a","b","c"]
43> hd(ListOfStrings).
"a"
lists:seq()
returns the equivalent of String.
Response to comment:
See lists:keyfind/3:
20> TargetRecord = lists:keyfind("xx", 3, Records).
#codes{letter = "C",braille = "xx"}
21> rr(my). %Read record definition contained in my.erl into the shell.
[codes]
22> TargetRecord#codes.letter.
"C"
The string "C"
is actually the list [67]
, which the shell has decided to display as "C". You need to be able to look up an ascii table to discover what a string really represents in Erlang. Or, you can get the ascii code of a character like this:
24> $C.
67
25> $a.
97
So, "C"
is actually the list [67]
, and "a"
is actually the list [97].
Upvotes: 6