Erlang conversion for one format to another format - erlang

How to convert this string format "{hari, localost}" into this: {"hari", "localost"}, in Erlang?
I tried to convert this format with lot of trial and error method, but I can't get the solution.

I guess you need to convert from string, so you can use the modules erl_scan and erl_parse:
1> erl_scan:string("{hari, localost}"++".").
{ok,[{'{',1},
{atom,1,hari},
{',',1},
{atom,1,localost},
{'}',1},
{dot,1}],
1}
2> {ok,Term} = erl_parse:parse_term(Tokens).
{ok,{hari,localost}}
3>Conv = fun({X, Y}) -> {atom_to_list(X), atom_to_list(Y)} end.
#Fun<erl_eval.6.80484245>
4> Conv(Term).
{"hari","localost"}
5>
Note 1 the function erl_parse:parse_term/1 will work only if Terms is a valid expression, it is why I had to add a "." at the end of the input.
Note 2 yo can directly transform to the final expression if you quote the terms in the input expression:
1> {ok,Tokens,_} = erl_scan:string("{\"hari\", \"localost\"}.").
{ok,[{'{',1},
{string,1,"hari"},
{',',1},
{string,1,"localost"},
{'}',1},
{dot,1}],
1}
2> {ok,Term} = erl_parse:parse_term(Tokens).
{ok,{"hari","localost"}}
3>

Related

String function clause matching

I'm running into a problem when writing some simple erlang code for an old Advent of Code task.
The following program is supposed to read lines, group characters in a string by occurrence and then count the number of lines that have a repeat of three characters.
count_occurrences([], Map) -> Map;
count_occurrences([H | T], Map) ->
count_occurrences(T, maps:put(H, maps:get(H, Map, 0) + 1, Map)).
count(Line, Count) ->
Map = count_occurrences(Line, #{}),
case lists:member(3, maps:values(Map)) of
true -> Count + 1;
false -> Count
end.
run() ->
{ok, Binary} = file:read_file("data.txt"),
Lines = binary:split(Binary, <<"\n">>, [global]),
Result = lists:foldl(fun count/2, 0, Lines),
Result.
However, I get this error message:
10> c(day2).
{ok,day2}
11> day2:run().
** exception error: no function clause matching day2:count_occurrences(<<"bpacnmelhhzpygfsjoxtvkwuor">>,#{}) (day2.erl, line 5)
in function day2:count/2 (day2.erl, line 10)
in call from lists:foldl/3 (lists.erl, line 1263)
I don't understand why <<"bpacnmelhhzpygfsjoxtvkwuor">>,#{} doesn't match the second "count_occurrences" function clause - a string is the same as a list, right? Why doesn't it match [H | T]?
Check out this example:
-module(a).
-compile(export_all).
go([_H|_T], _X) ->
"First arg was a list";
go("a", _X) ->
"First arg was a string";
go(<<"a">>, _X) ->
"First arg was a binary".
In the shell:
5> a:go(<<"a">>, #{a=>1, b=>2}).
"First arg was a binary"
and:
6> a:go("a", #{a=>1, b=>2}).
"First arg was a list"
a string is the same as a list, right?
Yes, a double quoted string is a shortcut for creating a list of integers where the integers in the list are the ascii codes of the characters. Hence, the second function clause above will never match:
a.erl:6: Warning: this clause cannot match because a previous clause
at line 4 always matches
But....a binary, such as <<"abc">> is NOT a string, and therefore a binary is not a shortcut for creating a list of integers.
8> "a" =:= [97].
true
Okay, you knew that. But, now:
9> "a" =:= <<"a">>.
false
10> <<"a">> =:= <<97>>.
true
11> "a" =:= <<97>>.
false
And, finally:
13> <<"abc">> =:= <<97, 98, 99>>.
true
The last example shows that specifying a double quoted string inside a binary is just a shortcut for specifying a comma separated list of integers inside a binary--however specifying a double quoted string inside a binary does not somehow convert the binary to a list.
Note that you can also iterate through a binary with only slightly different syntax:
count_occurrences(<<>>, Map) -> Map;
count_occurrences(<<H, T/binary>>, Map) ->
count_occurrences(T, maps:put(H, maps:get(H, Map, 0) + 1, Map)).
By default, H is assumed to be a byte, but you can add modifiers to specify how many bits you want to select, and more. See the documentation for the Bit Syntax.
You get this error cuz function count_occurrences/2 expect first argument list - [<<"bpacnmelhhzpygfsjoxtvkwuor">>] or "bpacnmelhhzpygfsjoxtvkwuor" but was put binary - <<"bpacnmelhhzpygfsjoxtvkwuor">>. Double check input data Line in function count/2 of module day2.erl at line 10:
1> is_list([]).
true
2> is_list("").
true
3> is_list(<<"">>).
false
4> is_list(binary_to_list(<<"">>)).
true

How to take input as tuple and store it in a variable in Erlang?

I want to take input from user and store it in a variable so that I pass this to another function.
Thanks in advance..
According to IO module manual you can use io:fread/2, io:get_chars/2, io:get_line/1 or io:read/1.
For example:
% get input in desired form in string and you need to parse it.
% each ~ts means that I want a unicode string.
1> {ok, [FirstName, LastName]} = io:fread("what is your name? ", "~ts ~ts").
what is your name? foo bar
{ok,["foo","bar"]}
2> FirstName.
"foo"
3> LastName.
"bar"
% get input for defined length in string and you need to parse it:
4> NumberOfCharacters = 7.
7
5> FullName = io:get_chars("what is your name? ", NumberOfCharacters).
what is your name? foo bar
"foo bar"
6> FullName.
"foo bar"
% get whole line as input in string and you need to parse it:
7> FullName2 = io:get_line("what is your name? ").
what is your name? foo bar
"foo bar\n"
8> FullName2.
"foo bar\n"
% get Erlang terms as input:
9> {ok, {FirstNameAtom, LastNameAtom}=FullNameTuple} = io:read("what is your name? ").
what is your name? {foo, bar}.
{ok,{foo,bar}}
10> FirstNameAtom.
foo
11> LastNameAtom.
bar
12> FullNameTuple.
{foo,bar}
13> {ok, Input} = io:read("enter text? ").
enter text? {100,c}.
{ok,{100,c}}
14> Input.
{100,c}
1> {ok, [T]} = io:fread("enter text: ", "~s").
enter text: {100,c}
{ok,["{100,c}"]}
2> T.
"{100,c}"
Then you can get needed values like this:
5> {ok, Tokens, _} = erl_scan:string(T).
{ok,[{'{',1},{integer,1,100},{',',1},{atom,1,c},{'}',1}],1}
6> Tokens.
[{'{',1},{integer,1,100},{',',1},{atom,1,c},{'}',1}]
7>{_, _, A1} = lists:nth(2, Tokens).
{integer,1,100}
8> {_, _, A2} = lists:nth(4, Tokens).
{atom,1,c}
9> {A1, A2}
{100, c}

Erlang: Get first n characters of a string

I have credit card number, let's say 5940043543536. And for security purposes I only want to display the first four digits.
How would one do that in erlang?
A string in Erlang is just a list of integers, so you can use lists:sublist/3:
1> String = "5940043543536".
"5940043543536"
2> lists:sublist(String, 1, 4).
"5940"
Note that the position argument starts from 1 and not 0.
In case you are receiving binary (instead of string)
binary:part(<<"123455678901234">>, 1, 4).
<<"2345">>
or if you need get last four digits
binary:part(<<"123455678901234">>, {byte_size(<<"123455678901234">>), -4}).
<<"1234">>
newer versions of Erlang have built in string functions. For your case
1> string:slice("123455678901234", 1, 4).
"1234"
there is a string:substring function too, which works the same way, but it has been depreciated for slice.
You can try use pattern matching:
1> String = "5940043543536".
"5940043543536"
2> [A,B,C,D|_] = String.
"5940043543536"
3> [A,B,C,D].
"5940"
Or you can create your own function, eg:
1> String = "5940043543536".
"5940043543536"
2> GetDigits = fun F(_, Acc, 0) -> lists:reverse(Acc);
F([H|T], Acc, N) -> F(T, [H|Acc], N - 1) end.
#Fun<erl_eval.43.91303403>
3> GetDigits(String, [], 4).
"5940"

Find substring in a string using start and end points from List

I have a list like List = [{0,12},{0,12},{-1,0},{0,12},{0,4},{1,2}] and a string Str = "https://www.youtube.com/watch?v=WQfdwsPao9E", now I've to find all the substrings using start and end point from list.
I want substrings to be returned in a List like ["https://www","https://www",..]
I tried using this:
C=lists:map(fun({X,Y}) -> string:sub_string(Str,X,Y) end,List)
1> List = [{0,12},{0,12},{-1,0},{0,12},{0,4},{1,2}].
[{0,12},{0,12},{-1,0},{0,12},{0,4},{1,2}]
2> Str = "https://www.youtube.com/watch?v=WQfdwsPao9E".
"https://www.youtube.com/watch?v=WQfdwsPao9E"
3> Len = length(Str).
43
4> [string:sub_string(Str,max(1,X),min(Len,Y)) || {X,Y} <- List].
["https://www.","https://www.",[],"https://www.","http",
"ht"]
5>
you may have to adjust the indexes in the string to fit exactly to your need.
[edit] It looks like I didn't interpret correctly what is the meaning of the tuple. I think it is {Fist_Char_Index, Char_Number}, or {-1,0} if no match is found. So you should use:
[string:sub_string(Str,X+1,X+Y) || {X,Y} <- List, {X,Y} =/= {-1,0}].

Erlang converting proplist to dict

I'm new to Erlang and am trying to convert something like the following to a dict:
{struct,[{<<"1">>,<<"2,3,4">>},{<<"2">>,<<"2,3,4">>}]}
I'm getting this after decoding the following json using mochijson2:
<<"{"1":"2,3,4","2":"2,3,4"}">>
The final result I'm looking for would be something like:
1 -> [2,3,4]
2 -> [2,3,4]
I think it's a proplist but not sure how to proceed with the conversion. Thanks
I'm not sure what you are asking for but this is may be it:
1> Term = {struct,[{<<"1">>,<<"2,3,4">>},{<<"2">>,<<"2,3,4">>}]}.
{struct,[{<<"1">>,<<"2,3,4">>},{<<"2">>,<<"2,3,4">>}]}
2> {struct, PropList} = Term.
{struct,[{<<"1">>,<<"2,3,4">>},{<<"2">>,<<"2,3,4">>}]}
3> Dict = dict:from_list(PropList).
{dict,2,16,16,8,80,48,
{[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]},
{{[],[],[],[],[],[],[],[],[],[],[],
[[<<"2">>|<<"2,3,4">>]],
[],[],
[[<<"1">>|<<"2,3,"...>>]],
[]}}}
4> dict:fetch_keys(Dict).
[<<"2">>,<<"1">>]
5> dict:fetch(<<"1">>, Dict).
<<"2,3,4">>

Resources