Related
Using SWI-Prolog I have made this simple predicate that relates a time that is in hh:mm format into a time term.
time_string(time(H,M), String) :-
number_string(H,Hour),
number_string(M,Min),
string_concat(Hour,":",S),
string_concat(S,Min,String).
The predicate though can only work in one direction.
time_string(time(10,30),String).
String = "10:30". % This is perfect.
Unfortunately this query fails.
time_string(Time,"10:30").
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR: [11] number_string(_8690,_8692)
ERROR: [10] time_string(time(_8722,_8724),"10:30") at /tmp/prolcompDJBcEE.pl:74
ERROR: [9] toplevel_call(user:user: ...) at /usr/local/logic/lib/swipl/boot/toplevel.pl:1107
It would be really nice if I didn't have to write a whole new predicate to answer this query. Is there a way I could do this?
Well, going from the structured term time(H,M) to the string String is easier than going from the unstructured String the term time(H,M).
Your predicate works in the "generation" direction.
For the other direction, you want to parse the String. In this case, this is computationally easy and can be done without search/backtracking, which is nice!
Use Prolog's "Definite Clause Grammar" syntax which are "just" a nice way to write predicates that process a "list of stuff". In this case the list of stuff is a list of characters (atoms of length 1). (For the relevant page from SWI-Prolog, see here)
With some luck, the DCG code can run backwards/forwards, but this is generally not the case. Real code meeting some demands of efficiency or causality may force it so that under the hood of a single predicate, you first branch by "processing direction", and then run through rather different code structures to deliver the goods.
So here. The code immediately "decays" into the parse and generate branches. Prolog does not yet manage to behave fully constraint-based. You just have to do some things before others.
Anyway, let's do this:
:- use_module(library(dcg/basics)).
% ---
% "Generate" direction; note that String may be bound to something
% in which case this clause also verifies whether generating "HH:MM"
% from time(H,M) indeed yields (whatever is denoted by) String.
% ---
process_time(time(H,M),String) :-
integer(H), % Demand that H,M are valid integers inside limits
integer(M),
between(0,23,H),
between(0,59,M),
!, % Guard passed, commit to this code branch
phrase(time_g(H,M),Chars,[]), % Build Codes from time/2 Term
string_chars(String,Chars). % Merge Codes into a string, unify with String
% ---
% "Parse" direction.
% ---
process_time(time(H,M),String) :-
string(String), % Demand that String be a valid string; no demands on H,M
!, % Guard passed, commit to this code branch
string_chars(String,Chars), % Explode String into characters
phrase(time_p(H,M),Chars,[]). % Parse "Codes" into H and M
% ---
% "Generate" DCG
% ---
time_g(H,M) --> hour_g(H), [':'], minute_g(M).
hour_g(H) --> { divmod(H,10,V1,V2), digit_int(D1,V1), digit_int(D2,V2) }, digit(D1), digit(D2).
minute_g(M) --> { divmod(M,10,V1,V2), digit_int(D1,V1), digit_int(D2,V2) }, digit(D1), digit(D2).
% ---
% "Parse" DCG
% ---
time_p(H,M) --> hour_p(H), [':'], minute_p(M).
hour_p(H) --> digit(D1), digit(D2), { digit_int(D1,V1), digit_int(D2,V2), H is V1*10+V2, between(0,23,H) }.
minute_p(M) --> digit(D1), digit(D2), { digit_int(D1,V1), digit_int(D2,V2), M is V1*10+V2, between(0,59,M) }.
% ---
% Do I really have to code this? Oh well!
% ---
digit_int('0',0).
digit_int('1',1).
digit_int('2',2).
digit_int('3',3).
digit_int('4',4).
digit_int('5',5).
digit_int('6',6).
digit_int('7',7).
digit_int('8',8).
digit_int('9',9).
% ---
% Let's add plunit tests!
% ---
:- begin_tests(hhmm).
test("parse 1", true(T == time(0,0))) :- process_time(T,"00:00").
test("parse 2", true(T == time(12,13))) :- process_time(T,"12:13").
test("parse 1", true(T == time(23,59))) :- process_time(T,"23:59").
test("generate", true(S == "12:13")) :- process_time(time(12,13),S).
test("verify", true) :- process_time(time(12,13),"12:13").
test("complete", true(H == 12)) :- process_time(time(H,13),"12:13").
test("bad parse", fail) :- process_time(_,"66:66").
test("bad generate", fail) :- process_time(time(66,66),_).
:- end_tests(hhmm).
That's a lot of code.
Does it work?
?- run_tests.
% PL-Unit: hhmm ........ done
% All 8 tests passed
true.
Given the simplicity of the pattern, a DCG could be deemeed overkill, but actually it provides us an easy access to the atomics ingredients that we can feed into some declarative arithmetic library. For instance
:- module(hh_mm_bi,
[hh_mm_bi/2
,hh_mm_bi//1
]).
:- use_module(library(dcg/basics)).
:- use_module(library(clpfd)).
hh_mm_bi(T,S) :- phrase(hh_mm_bi(T),S).
hh_mm_bi(time(H,M)) --> n2(H,23),":",n2(M,59).
n2(V,U) --> d(A),d(B), {V#=A*10+B,V#>=0,V#=<U}.
d(V) --> digit(D), {V#=D-0'0}.
Some tests
?- hh_mm_bi(T,`23:30`).
T = time(23, 30).
?- hh_mm_bi(T,`24:30`).
false.
?- phrase(hh_mm_bi(T),S).
T = time(0, 0),
S = [48, 48, 58, 48, 48] ;
T = time(0, 1),
S = [48, 48, 58, 48, 49] ;
...
edit
library(clpfd) is not the only choice we have for declarative arithmetic. Here is another shot, using library(clpBNR), but it requires you install the appropriate pack, using ?- pack_install(clpBNR). After this is done, another solution functionally equivalent to the one above could be
:- module(hh_mm_bnr,
[hh_mm_bnr/2
,hh_mm_bnr//1
]).
:- use_module(library(dcg/basics)).
:- use_module(library(clpBNR)).
hh_mm_bnr(T,S) :- phrase(hh_mm_bnr(T),S).
hh_mm_bnr(time(H,M)) --> n2(H,23),":",n2(M,59).
n2(V,U) --> d(A),d(B), {V::integer(0,U),{V==A*10+B}}.
d(V) --> digit(D), {{V==D-0'0}}.
edit
The comment (now removed) by #DavidTonhofer has made me think that a far simpler approach is available, moving the 'generation power' into d//1:
:- module(hh_mm,
[hh_mm/2
,hh_mm//1
]).
hh_mm(T,S) :- phrase(hh_mm(T),S).
hh_mm(time(H,M)) --> n2(H,23),":",n2(M,59).
n2(V,U) --> d(A),d(B), { V is A*10+B, V>=0, V=<U }.
d(V) --> [C], { member(V,[0,1,2,3,4,5,6,7,8,9]), C is V+0'0 }.
time_string(time(H,M),String)
:-
hour(H) ,
minute(M) ,
number_string(H,Hs) ,
number_string(M,Ms) ,
string_concat(Hs,":",S) ,
string_concat(S,Ms,String)
.
hour(H) :- between(0,11,H) .
minute(M) :- between(0,59,M) .
/*
?- time_string(time(10,30),B).
B = "10:30".
?- time_string(time(H,M),"10:30").
H = 10,
M = 30 ;
false.
?- time_string(time(H,M),S).
H = M, M = 0,
S = "0:0" ;
H = 0,
M = 1,
S = "0:1" ;
H = 0,
M = 2,
S = "0:2" ;
H = 0,
M = 3,
S = "0:3" %etc.
*/
Yet another answer, avoiding DCGs as overkill for this task. Or rather, the two separate tasks involved here: Not every relation can be expressed in a single Prolog predicate, especially not every relation on something as extra-logical as SWI-Prolog's strings.
So here is the solution for one of the tasks, computing strings from times (this is your code renamed):
time_string_(time(H,M), String) :-
number_string(H,Hour),
number_string(M,Min),
string_concat(Hour,":",S),
string_concat(S,Min,String).
For example:
?- time_string_(time(11, 59), String).
String = "11:59".
Here is a simple implementation of the opposite transformation:
string_time_(String, time(H, M)) :-
split_string(String, ":", "", [Hour, Minute]),
number_string(H, Hour),
number_string(M, Minute).
For example:
?- string_time_("11:59", Time).
Time = time(11, 59).
And here is a predicate that chooses which of these transformations to use, depending on which arguments are known. The exact condition will depend on the cases that can occur in your application, but it seems reasonable to say that if the string is indeed a string, we want to try to parse it:
time_string(Time, String) :-
( string(String)
-> % Try to parse the existing string.
string_time_(String, Time)
; % Hope that Time is a valid time term.
time_string_(Time, String) ).
This will translate both ways:
?- time_string(time(11, 59), String).
String = "11:59".
?- time_string(Time, "11:59").
Time = time(11, 59).
I am new to elixir and I need to create ISO 8583 client with this language and Phoenix framework. I found an Erlang library for it from stackoverflow thread here, compiled successfully and followed the example in the repository here but got error when marshaling the message. Here is my Elixir code to marshal the message:
msg1 = :erl8583_message.new()
msg2 = :erl8583_message.set_mti("0800", msg1)
msg3 = :erl8583_message.set(3, "300000", msg2)
msg4 = :erl8583_message.set(24, "045", msg3)
msg5 = :erl8583_message.set(41, "11111111", msg4)
msg6 = :erl8583_message.set(42, "222222222222222", msg5)
msg7 = :erl8583_message.set(63, "This is a Test Message", msg6)
marshalled = :erl8583_marshaller_ascii.marshal(msg7)
That's just an elixir version from the example on the repo. This is the error I've got when running the app:
[error] #PID<0.438.0> running TestlangIsoClientWeb.Endpoint (cowboy_protocol) terminated
Server: 127.0.0.1:4001 (http)
Request: POST /api/process
** (exit) an exception was raised:
** (FunctionClauseError) no function clause matching in :erl8583_marshaller_ascii.marshal_data_element/2
(erl8583) /home/muhammad/Workspace/testlang/testlang_iso_client/deps/erl8583/src/erl8583_marshaller_ascii.erl:168: :erl8583_marshaller_ascii.marshal_data_element({:n, :fixed, 4}, "0800")
(erl8583) /home/muhammad/Workspace/testlang/testlang_iso_client/deps/erl8583/src/erl8583_marshaller.erl:108: :erl8583_marshaller.marshal/2
(testlang_iso_client) lib/testlang_iso_client_web/controllers/my_controller.ex:61: TestlangIsoClientWeb.MyController.process/2
(testlang_iso_client) lib/testlang_iso_client_web/controllers/my_controller.ex:1: TestlangIsoClientWeb.MyController.action/2
(testlang_iso_client) lib/testlang_iso_client_web/controllers/my_controller.ex:1: TestlangIsoClientWeb.MyController.phoenix_controller_pipeline/2
(testlang_iso_client) lib/testlang_iso_client_web/endpoint.ex:1: TestlangIsoClientWeb.Endpoint.instrument/4
(phoenix) lib/phoenix/router.ex:278: Phoenix.Router.__call__/1
(testlang_iso_client) lib/testlang_iso_client_web/endpoint.ex:1: TestlangIsoClientWeb.Endpoint.plug_builder_call/2
(testlang_iso_client) lib/testlang_iso_client_web/endpoint.ex:1: TestlangIsoClientWeb.Endpoint.call/2
(plug) lib/plug/adapters/cowboy/handler.ex:16: Plug.Adapters.Cowboy.Handler.upgrade/4
(cowboy) /home/muhammad/Workspace/testlang/testlang_iso_client/deps/cowboy/src/cowboy_protocol.erl:442: :cowboy_protocol.execute/4
Is there something I missed to make it work? Any help would be very appreciated.
Updated
I have tried to changed the string parameter to charlist, but still got the same error. Here is the code snippet:
def test(conn, _params) do
IO.puts("Test")
msg1 = :erl8583_message.new()
msg2 = :erl8583_message.set_mti('0800', msg1)
msg3 = :erl8583_message.set(3, '300000', msg2)
msg4 = :erl8583_message.set(24, '045', msg3)
msg5 = :erl8583_message.set(41, '11111111', msg4)
msg6 = :erl8583_message.set(42, '222222222222222', msg5)
msg7 = :erl8583_message.set(63, 'This is a Test Message', msg6)
marshalled = :erl8583_marshaller_ascii.marshal(msg7)
json(conn, %{status: "ok"})
end
Here is the function erl8583_marshaller.erl:108 mentioned in the stacktrace:
marshal(Message, MarshalHandlers) ->
OptionsRecord = parse_options(MarshalHandlers, #marshal_options{}),
{Marshalled1, Message1} = init_marshalling(OptionsRecord, Message),
MarshalledMti = encode_mti(OptionsRecord, Message1), % --- Line 108
Marshalled2 = <<Marshalled1/binary, MarshalledMti/binary>>,
{MarshalledBitmap, Message2} = encode_bitmap(OptionsRecord, Message1),
Marshalled3 = <<Marshalled2/binary, MarshalledBitmap/binary>>,
MarshalledFields = encode_fields(OptionsRecord, Message2),
Marshalled4 = <<Marshalled3/binary, MarshalledFields/binary>>,
end_marshalling(OptionsRecord, Message2, Marshalled4).
And here is the function erl8583_marshaller_ascii.erl:168 mentioned in the stacktrace:
%%
%% Local Functions
%%
marshal_data_element({n, llvar, Length}, FieldValue) when length(FieldValue) =< Length ->
erl8583_convert:integer_to_string(length(FieldValue), 2) ++ FieldValue;
I don't understand why the call to that function was failed to match with parameters {:n, :fixed, 4}, "0800" that was sent from my function. I have tried to change the double quotes to single quotes with no success. Is there any other suggestions what am I supposed to do?
there may be a bug in the code.
you can reference this issue here
there is one elixir library out which is relatively new.
its called ale8583.
documentation is still coming out on this one but looks very promising.
you can check it out.
Try passing charlists instead of strings:
msg1 = :erl8583_message.new()
msg2 = :erl8583_message.set_mti('0800', msg1)
msg3 = :erl8583_message.set(3, '300000', msg2)
msg4 = :erl8583_message.set(24, '045', msg3)
msg5 = :erl8583_message.set(41, '11111111', msg4)
msg6 = :erl8583_message.set(42, '222222222222222', msg5)
msg7 = :erl8583_message.set(63, 'This is a Test Message', msg6)
marshalled = :erl8583_marshaller_ascii.marshal(msg7)
There is potential for confusion here:
What Erlang calls "strings" and puts in double quotes ("foo"), Elixir calls "charlists" and puts in single quotes ('foo').
What Elixir calls "strings" and puts in double quotes ("foo"), Erlang calls "binaries" and puts in double quotes plus angle brackets (<<"foo">>).
It seems like the erl8583 library expects Erlang strings throughout.
I query the list of users from Mnesia Database in Chicagoboss. I'm getting the error when I try to add the Lists within lists:foreach with ++ operator. My aim is, based on userid I will do ets:lookup to my cache and create a List like - [{{<<"name">>,<<"Batman">>}, {<<"steps">>,2552}, {<<"distance">>,2050}}].
For each user I'll create this list and add with the previous List. So that ultimately I can can sort on <<"steps">> and convert the binary list by json encoding and send it to the client via Websockets.
I'm getting the error at this line:
Reading1 = Reading2 ++ Currentlist
as I've decalred Reading1 as an Empty list.
My question is how can I manipulate the lists within the lists:foreach and then send the result List via websocket?
BelugaUsers = boss_db:find(users, [{accesstoken, 'not_equals', ''}]),
Reading1 = [],
Reading2 = [],
lists:foreach(fun(X) ->
{_,_,BEmail,BName,_,_,BAccessToken,_} = X,
UserKey = BEmail ++ "-" ++ ?MYAPICALL1,
io:format("UserKey for Leader Board: ~n~p~n",[UserKey]),
[Reading] = ets:lookup(myapi_cache, list_to_binary(UserKey)),
{_,Result} = Reading,
ActivitySummary = proplists:get_value(<<"activitySummary">>, Result),
%Print ActivitySummary for the user ....printing fine
io:format("ActivitySummary ==========: ~n~p~n",[ActivitySummary]),
%Create a list of the format
%[{{<<"name">>,<<"Batman">>}, {<<"steps">>,2552}, {<<"distance">>,2050}}]
Currentlist = [{{<<"name">>, list_to_binary(BName)}, {<<"steps">>, proplists:get_value(<<"steps">>, ActivitySummary)}, {<<"distance">>, proplists:get_value(<<"distance">>, ActivitySummary)}}],
%% HERE I'M GETTING error%%
Reading1 = Reading2 ++ Currentlist
end, BelugaUsers),
%sort the list
Reading3 = lists:keysort(2, Reading1),
%reverse the list
Reading4 = lists:reverse(Reading3),
WebSocketId ! {text, jsx:encode(Reading4)},
Erlang variables are single-assignment; once bound to a value, they can't be re-bound to a different value.
The lists:foreach/2 function is not useful for this problem because it can't create a new value and return it to its caller. You should instead use lists:map/2, perhaps like this:
BelugaUsers = boss_db:find(users, [{accesstoken, 'not_equals', ''}]),
Reading = lists:map(
fun(X) ->
{_,_,BEmail,BName,_,_,BAccessToken,_} = X,
UserKey = BEmail ++ "-" ++ ?MYAPICALL1,
io:format("UserKey for Leader Board: ~n~p~n",[UserKey]),
{_,Result} = hd(ets:lookup(myapi_cache, list_to_binary(UserKey))),
ActivitySummary = proplists:get_value(<<"activitySummary">>, Result),
%%Print ActivitySummary for the user ....printing fine
io:format("ActivitySummary ==========: ~n~p~n",[ActivitySummary]),
%%Create a tuple of the format
%%{{<<"name">>,<<"Batman">>}, {<<"steps">>,2552}, {<<"distance">>,2050}}
{{<<"name">>, list_to_binary(BName)},
{<<"steps">>, proplists:get_value(<<"steps">>, ActivitySummary)},
{<<"distance">>, proplists:get_value(<<"distance">>, ActivitySummary)}}
end, BelugaUsers),
%%sort the list
Reading2 = lists:keysort(2, Reading),
%%reverse the list
Reading3 = lists:reverse(Reading2),
WebSocketId ! {text, jsx:encode(Reading3)}.
The lists:map/2 function applies a function to each value in a list to a produce a potentially different value and returns a new list consisting of those new values. This is essentially what you were trying to do with lists:foreach/2 and your attempt to use imperative assignment to add each element to an already-existing list.
You could alternatively use a list comprehension but I think lists:map/2 is clearer in this situation.
I have a big list of some forms with data that needs to be concated with other data from others forms with the same name.
The list format is quite complex and looks like this:
[[{EVAL_SEQ_1, {FORMNAME, ListDataToConcat1}}], [{EVAL_SEQ_2, {FORMNAME, ListDataToConcat2}}], ...]
This is the output that I want:
[[{EVAL_SEQ_1, {FORMNAME, ListDataToConcat1 + ListDataToConcat2}}]}}] ...]
Where:
EVAL_SEQ_1 = Form Sequence Number,
FORMNAME = Form Name
ListDataToConcat = List that Needs to concat
eg.Here is my sample data:
[[{"eval_data_12",
{<<"prvl_mobable_asset_0000_h200401">>,
[{'F_01_0100',[1]},
{'F_01_0090',["3"]},
{'F_01_0080',[]},
{'F_01_0070',[9999]},
{'F_01_0060',[{era,0},{year,[]},{month,[]}]},
{'F_01_0050',[]},
{'F_01_0040',[]},
{'F_01_0030',[]},
{'F_01_0020',<<>>},
{'F_01_0010',<<"4 - 8">>}]}}],
[{"eval_data_11",
{<<"prvl_mobable_asset_0000_h200401">>,
[{'F_01_0100',[]},
{'F_01_0090',["2"]},
{'F_01_0080',[]},
{'F_01_0070',[22222]},
{'F_01_0060',[{era,0},{year,[]},{month,[]}]},
{'F_01_0050',[]},
{'F_01_0040',[]},
{'F_01_0030',[]},
{'F_01_0020',<<>>},
{'F_01_0010',<<"4 - 1">>}]}}], ...]
I want the resultant output like this:
[{"eval_data_11",
{<<"prvl_mobable_asset_0000_h200401">>,
[{'F_01_0100',[[], [1]]},
{'F_01_0090',[["2"], ["3"]]},
{'F_01_0080',[[], []]},
{'F_01_0070',[[22222], [9999]]},
{'F_01_0060',[[{era,0},{year,[]},{month,[]}], [{era,0},{year,[]},{month,[]}]]},
{'F_01_0050',[[], []]},
{'F_01_0040',[[], []]},
{'F_01_0030',[[], []]},
{'F_01_0020',[[<<>>], [<<>>]]},
{'F_01_0010',[[<<"4 - 1">>], [<<"4 - 8">>]}]}}]
I propose you this solution:
[edit]
I modified the code to answer your last comment, there are still fuzzy things:
if Assets are different, creates different record list?
if not what should be done with Asset name? I have chosen to keep the "smallest one"
is the order of records important - I decided no
One remark, I am missing some context, but If I add to collect such informations, I would store it in an ets table. It is faster to update, easy to traverse, and easy to transform into list if needed.
-module (t).
-compile([export_all]).
% rec = {atom,term}
% reclist = [rec,...]
% asset = {bin,reclist}
% eval_data = [{list,asset}]
% eval_set = [eval_data,...]
% recs = {atom,[term]}
% recslist = [recs,...]
addrec({Key,Val},Recslist) ->
Val_list = proplists:get_value(Key, Recslist, []),
[{Key,[Val|Val_list]}|proplists:delete(Key,Recslist)].
merge_rec(Reclist,Recslist) -> lists:foldl(fun(Rec,Acc) -> addrec(Rec,Acc) end,Recslist,Reclist).
merge_eval([{Eval,{Asset,Reclist}}],[]) ->
[{Eval,{Asset,[{Key,[Val]} || {Key,Val} <- Reclist]}}];
merge_eval([{Eval,{Asset,Reclist}}],[{Eval_low,{Asset_low,Recslist}}]) ->
[{min(Eval,Eval_low),{min(Asset,Asset_low),merge_rec(Reclist,Recslist)}}].
merge_set(Eval_set) -> lists:foldl(fun(Eval_data,Acc) -> merge_eval(Eval_data,Acc) end,[],Eval_set).
test() ->
Eval_set = [[{"eval_data_10",
{<<"prvl_mobable_asset_0000_h200401">>,
[{'F_01_0100',[1]},
{'F_01_0090',["3"]},
{'F_01_0080',[]},
{'F_01_0070',[9999]},
{'F_01_0060',[{era,0},{year,[]},{month,[]}]},
{'F_01_0050',[]},
{'F_01_0040',[]},
{'F_01_0030',[]},
{'F_01_0020',<<>>},
{'F_01_0010',<<"4 - 8">>}]}}],
[{"eval_data_11",
{<<"prvl_mobable_asset_0000_h200401">>,
[{'F_01_0100',[]},
{'F_01_0090',["2"]},
{'F_01_0080',[]},
{'F_01_0070',[22222]},
{'F_01_0060',[{era,0},{year,[]},{month,[]}]},
{'F_01_0050',[]},
{'F_01_0040',[]},
{'F_01_0030',[]},
{'F_01_0020',<<>>},
{'F_01_0010',<<"4 - 1">>}]}}]],
merge_set(Eval_set).
#trex:
FormList = [[{EVAL_SEQ_1, {FORMNAME, ListDataToConcat1}}], [{EVAL_SEQ_2, {FORMNAME, ListDataToConcat2}}], ....]
You will need to get a separate the list which has common form names as <<"prvl_mobable_asset_0000_h200401">>
{MobableList, EvalDataList} = lists:partition(fun([{EVAL_SEQ, {FORMNAME, ListData}}]) ->
FORMNAME == <<"prvl_mobable_asset_0000_h200401">>
end, FormList),
Then, Get a separate Tuple of Form sequences and Lists. To separate them
{EvalSeq, MergingList} = lists:foldl(fun(X, {EvalNames, OutList}) ->
[{EVAL_SEQ, {FORMNAME, ListData}}] = X,
{[EVAL_SEQ|EvalNames], [ListData|OutList]}
end, {[], []}, MobableList),
Hence, you will get the new tuple as :
{[EVAL_SEQ_1, EVAL_SEQ_2, EVAL_SEQ_3, ...], [ListDataToConcat1, ListDataToConcat2, ListDataToConcat3,...]}
I'm not sure which sequence Number you want as you havn't mentioned it clearly, Here is the way you can get the minimum Sequence Number.
Evalsequence = lists:min(EvalSeq),
Now merge your code using merge function as shown below or you can refer merging inner list Merge inner lists of a list erlang:
MergedList = merge(MergingList),
And finally a separate list as:
[{Evalsequence, {<<"prvl_mobable_asset_0000_h200401">>, MergedList}}].
merge(ListOfLists) ->
Combined = lists:append(ListOfLists),
Fun = fun(Key) -> {Key,proplists:get_all_values(Key,Combined)} end,
lists:map(Fun,proplists:get_keys(Combined)).
I try to get TO: user#mail.com field from mime mail message.
I have code:
parse_to(Data) ->
List = string:tokens(Data, ":"),
Sep1 = lists:map(fun(H) ->string:tokens(H, ":") end, List),
io:format(Sep1),
Sep2 = lists:filter(fun ([K | _]) -> K == "To" end, Sep1),
ListAddress = lists:append(Sep2),
[_ | Tail] = ListAddress,
lists:map(fun(Address) -> string:tokens(Address, ",") end, Tail).
If i have short message for example: https://gist.github.com/865910
I got in io:format(Sep1) https://gist.github.com/865905, it's ok all without :
But if i have long message with attachment: - https://gist.github.com/865914
I got in io:format(Sep1) - https://gist.github.com/865906 everything remains the same as it was with :
What's wrong? Why shot message normal parse and big message not parsed?
When i try use regexp:
List = binary_to_list(Binary),
re:run(List, "^To: (.)*$", [multiline, {capture, all_but_first, list}]).
I get only {match, ["m"]}
Why?
Thank you.
Try a regular expression:
1> Data = <<"...">> % Your long message
<<"...">>
2> re:run(Data, <<"^To: (.*)$">>, [multiline, {capture, all_but_first, binary}]).
{match,[<<"shk#shk.dyndns-mail.com">>]}