-
Notifications
You must be signed in to change notification settings - Fork 74
/
Copy pathcsvkv.erl
81 lines (67 loc) · 2.4 KB
/
csvkv.erl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
%%%===================================================================
%%% @copyright (C) 2012, Erlang Solutions Ltd.
%%% @doc Module for parsing DIGEST-MD5 - style k1=v1,k2="v2" content
%%% @end
%%%===================================================================
-module(csvkv).
-export([parse/1, format/1, format/2]).
%%--------------------------------------------------------------------
%% Public API
%%--------------------------------------------------------------------
-spec parse(binary()) -> [{binary(), binary()}].
parse(Text) ->
do_parse(rev_lex(Text, []), []).
-spec format([{binary(), binary()}]) -> binary().
format(Items) ->
format(Items,true).
-spec format([{binary(), binary()}], boolean()) -> binary().
format(Items, QMark) ->
IOList = join([format_item(I, QMark) || I <- Items], $,),
list_to_binary(IOList).
%%--------------------------------------------------------------------
%% Implementation
%%--------------------------------------------------------------------
%% note: lexemes are in reverse order
do_parse([{v, V}, {k, K} | Rest], Acc) ->
do_parse(Rest, [{K, V} | Acc]);
do_parse([], Acc) ->
Acc.
%% note: returns lexemes in reverse order
rev_lex(<<>>, Acc) ->
Acc;
rev_lex(Text, Acc) ->
rev_lex_key(Text, Acc).
rev_lex_key(Text, Acc) ->
[Key, Rest] = binary:split(Text, <<"=">>),
rev_lex_value(Rest, [{k, Key} | Acc]).
rev_lex_value(<<"\"", Text/binary>>, Acc) ->
rev_lex_value_quoted(Text, <<>>, Acc);
rev_lex_value(Text, Acc) ->
rev_lex_value_bare(Text, Acc).
rev_lex_value_quoted(<<"\\\"",T/binary>>, Val, Acc) ->
rev_lex_value_quoted(T, <<Val/binary,"\"">>, Acc);
rev_lex_value_quoted(<<"\",",T/binary>>, Val, Acc) ->
rev_lex(T, [{v, Val} | Acc]);
rev_lex_value_quoted(<<"\"",T/binary>>, Val, Acc) ->
rev_lex(T, [{v, Val} | Acc]);
rev_lex_value_quoted(<<H,T/binary>>, Val, Acc) ->
rev_lex_value_quoted(T, <<Val/binary,H>>, Acc).
rev_lex_value_bare(Text, Acc) ->
case binary:split(Text, <<",">>) of
[Val, Rest] ->
rev_lex(Rest, [{v, Val} | Acc]);
[Val] ->
rev_lex(<<>>, [{v, Val} | Acc])
end.
join([], _) ->
[];
join(Items, Sep) ->
tl(lists:append([[Sep, I] || I <- Items])).
format_item({Key, Val}, QMark) ->
EscVal = re:replace(Val, "\"", "\\\"", [global]),
case QMark of
true ->
[Key, $=, $", EscVal, $"];
_ ->
[Key, $=, EscVal]
end.