diff --git a/src/hz_format.erl b/src/hz_format.erl index f9598e8..87d3b16 100644 --- a/src/hz_format.erl +++ b/src/hz_format.erl @@ -4,22 +4,22 @@ -module(hz_format). --export([price/1, price/2, price/3, price/4, -% read/1, read/2, +-export([amount/1, amount/2, amount/3, amount/4, + read/1, price_to_string/1, string_to_price/1]). --spec price(Pucks) -> Formatted +-spec amount(Pucks) -> Formatted when Pucks :: integer(), Formatted :: string(). %% @doc %% A convenience formatting function. -%% @equiv price(us, Pucks). +%% @equiv amount(us, Pucks). -price(Pucks) -> - price(us, Pucks). +amount(Pucks) -> + amount(us, Pucks). --spec price(Style, Pucks) -> Formatted +-spec amount(Style, Pucks) -> Formatted when Style :: us | jp | metric | heresy | {Separator, Span}, Separator :: $, | $_, Span :: 3 | 4, @@ -27,13 +27,13 @@ price(Pucks) -> Formatted :: string(). %% @doc %% A money formatting function. -%% @equiv price(gaju, Style, Pucks). +%% @equiv amount(gaju, Style, Pucks). -price(Style, Pucks) -> - price(gaju, Style, Pucks). +amount(Style, Pucks) -> + amount(gaju, Style, Pucks). --spec price(Unit, Style, Pucks) -> Formatted +-spec amount(Unit, Style, Pucks) -> Formatted when Unit :: gaju | puck, Style :: us | jp | metric | heresy | {Separator, Span}, Separator :: $, | $_, @@ -43,23 +43,23 @@ price(Style, Pucks) -> %% @doc %% A simplified format function covering the most common formats desired. -price(gaju, us, Pucks) -> +amount(gaju, us, Pucks) -> western($,, $., 3, all, Pucks); -price(puck, us, Pucks) -> +amount(puck, us, Pucks) -> western($,, 3, Pucks); -price(Unit, jp, Pucks) -> +amount(Unit, jp, Pucks) -> jp(Unit, all, Pucks); -price(Unit, metric, Pucks) -> +amount(Unit, metric, Pucks) -> bestern(Unit, ranks(metric), all, Pucks); -price(Unit, heresy, Pucks) -> +amount(Unit, heresy, Pucks) -> bestern(Unit, ranks(heresy), all, Pucks); -price(gaju, {Separator, Span}, Pucks) -> +amount(gaju, {Separator, Span}, Pucks) -> western(Separator, $., Span, all, Pucks); -price(puck, {Separator, Span}, Pucks) -> +amount(puck, {Separator, Span}, Pucks) -> western(Separator, Span, Pucks). --spec price(Unit, Style, Precision, Pucks) -> Serialized +-spec amount(Unit, Style, Precision, Pucks) -> Serialized when Unit :: gaju | puck, Style :: us | jp | metric | heresy | {Separator, Span}, Precision :: all | 0..18, @@ -71,53 +71,53 @@ price(puck, {Separator, Span}, Pucks) -> %% A flexible, if annoyingly complex, formatting function. %% %% ``` -%% price(gaju, us, 3, 123456789123456789123456789) -> +%% amount(gaju, us, 3, 123456789123456789123456789) -> %% "木123,456,789.123...". %% -%% price(gaju, us, 3, 123456789123000000000000000) -> +%% amount(gaju, us, 3, 123456789123000000000000000) -> %% "木123,456,789.123". %% -%% price(gaju, {$,, 3}, 3, 123456789123456789123456789) -> +%% amount(gaju, {$,, 3}, 3, 123456789123456789123456789) -> %% "木123,456,789.123...". %% -%% price(gaju, {$,, 3}, 6, 123456789123000000000000000) -> +%% amount(gaju, {$,, 3}, 6, 123456789123000000000000000) -> %% "木123,456,789.123" %% -%% price(gaju, {$_, 4}, 10, 123456789123456789123456789) -> +%% amount(gaju, {$_, 4}, 10, 123456789123456789123456789) -> %% "木1_2345_6789.1234_5678_91..." %% -%% price(gaju, jp, 3, 123456789123456789123456789) -> +%% amount(gaju, jp, 3, 123456789123456789123456789) -> %% "1億2345万6789木 12京3000兆本" %% -%% price(gaju, jp, 6, 123456789123456789123456789) -> +%% amount(gaju, jp, 6, 123456789123456789123456789) -> %% "1億2345万6789木 12京3456兆本" %% -%% price(gaju, jp, 0, 123456789123456789123456789) -> +%% amount(gaju, jp, 0, 123456789123456789123456789) -> %% "1億2345万6789木" %% -%% price(puck, jp, all, 123456789123456789123456789) -> +%% amount(puck, jp, all, 123456789123456789123456789) -> %% "123秭4567垓8912京3456兆7891億2345万6789本" %% ''' -price(gaju, us, Precision, Pucks) -> +amount(gaju, us, Precision, Pucks) -> western($,, $., 3, Precision, Pucks); -price(gaju, jp, Precision, Pucks) -> +amount(gaju, jp, Precision, Pucks) -> jp(gaju, Precision, Pucks); -price(gaju, metric, Precision, Pucks) -> +amount(gaju, metric, Precision, Pucks) -> bestern(gaju, ranks(metric), Precision, Pucks); -price(gaju, legacy, Precision, Pucks) -> +amount(gaju, legacy, Precision, Pucks) -> bestern(gaju, ranks(heresy), Precision, Pucks); -price(gaju, {Separator, Span}, Precision, Pucks) -> +amount(gaju, {Separator, Span}, Precision, Pucks) -> western(Separator, $., Span, Precision, Pucks); -price(puck, us, _, Pucks) -> +amount(puck, us, _, Pucks) -> western($,, 3, Pucks); -price(puck, jp, _, Pucks) -> +amount(puck, jp, _, Pucks) -> jp(puck, all, Pucks); -price(puck, metric, _, Pucks) -> +amount(puck, metric, _, Pucks) -> bestern(puck, ranks(metric), all, Pucks); -price(puck, legacy, _, Pucks) -> +amount(puck, legacy, _, Pucks) -> bestern(puck, ranks(heresy), all, Pucks); -price(puck, {Separator, Span}, _, Pucks) -> +amount(puck, {Separator, Span}, _, Pucks) -> western(Separator, Span, Pucks). @@ -165,7 +165,6 @@ western2(Separator, Break, Span, Precision, Pucks) -> end. decimal_pucks(all, PChars) -> - io:format("decimal_pucks: PChars: ~p~n", [PChars]), RTrailing = lists:reverse(PChars), {lists:reverse(lists:dropwhile(fun(C) -> C =:= $0 end, RTrailing)), ""}; decimal_pucks(Precision, PChars) -> @@ -401,121 +400,85 @@ puck_mark() -> $本. one_gaju() -> 1_000_000_000_000_000_000. -%-spec read(Format) -> Result -% when Format :: string(), -% Result :: {ok, Pucks} | {error, Reason}, -% Pucks :: integer(), -% Reason :: {badarg, Partial :: string(), Rest :: term()} -% | {incomplete, Partial :: string(), Rest :: binary()} -% | format. -%%% @doc -%%% Convery any valid string formatted representation and output a value in pucks. -%%% This routine can fail in the special case of `ch' style formatting with a single -%%% comma and/or a single period in it, as this can trigger misinterpretation as `us' -%%% style. When in doubt, always call `read/2' with a style specified. -% -%read(Format) -> -% case assess_style(string:trim(Format)) of -% us -> read(us, Format); -% ch -> read(ch, Format); -% jp -> read(jp, Format); -% Error -> Error -% end. -% -%assess_style([H1, H2 | Numbers]) -% when H1 =:= $木 orelse H1 =:= $本 orelse H2 =:= $木 orelse H2 =:= $本 -> -% case count($., Numbers) > 1 of -% false -> us; -% true -> ch -% end; -%assess_style(Format) -> -% case lists:member($木, Format) orelse lists:member($本, Format) of -% true -> jp; -% false -> {error, format} -% end. -% -%count(Char, String) -> count(Char, String, 0). -% -%count(C, [C | T], A) -> count(C, T, A + 1); -%count(C, [_ | T], A) -> count(C, T, A); -%count(_, [], A) -> A. -% -% -%-spec read(Style, Format) -> Result -% when Style :: us | jp | metric | legacy | undefined, -% Format :: string(), -% Result :: {ok, Pucks} | {error, Reason}, -% Pucks :: integer(), -% Reason :: {badarg, Partial :: string(), Rest :: term()} -% | {incomplete, Partial :: string(), Rest :: binary()} -% | format. -%%% @doc -%%% Convert any valid string formatted representation and output a value in pucks. -%%% Note that this function is deliberately a bit too permissive in the case of -%%% western formatting, stripping all non-halfwidth digit characters on the high -%%% and low sides of the format once the break (decimal) character is identified -%%% and sign is determined. That is to say, there are many ways to feed this wacky -%%% strings and get a number out of it, so be aware. -% -%read(Style, Format) -> -% case unicode:characters_to_list(Format) of -% String when is_list(String) -> -% Trimmed = string:trim(String), -% read2(Style, Trimmed); -% {error, Partial, Rest} -> -% {error, {badarg, Partial, Rest}}; -% Incomplete -> -% {error, Incomplete} -% end. -% -%read2(us, Format) -> -% read_western($., Format); -%read2(jp, Format) -> -% read_jp(Format); -%read2(undefined, Format) -> -% read(Format). -% -%read_western(Break, [$-, Format]) -> -% case read_western2(Break, Format) of -% {ok, Pucks} -> {ok, Pucks * -1}; -% Error -> Error -% end; -%read_western(Break, Format) -> -% read_western2(Break, Format). -% -%read_western2(Break, Format) -> -% case string:split(Format, [Break], all) of -% [[], L] -> read_western3(0, L); -% [H, []] -> read_western3(H, 0); -% [H, L] -> read_western3(H, L); -% [H] -> read_western3(H, 0); -% _ -> {error, format} -% end. -% -%read_western3(0, L) -> -% read_l(L); -%read_western3(H, 0) -> -% case read_h(H) of -% {ok, Gajus} -> {ok, Gajus * one_gaju()}; -% Error -> Error -% end; -%read_western3(H, L) -> -% Gajus = read_h(H), -% Pucks = read_l(L), -% {ok, (Gajus * one_gaju()) + Pucks}. -% -%read_h(S) -> -% case lists:filter(fun is_numchar/1, S) of -% [] -> 0; -% F -> list_to_integer(Filtered) -% end. -% -%read_l(L) -> -% case lists:filter(fun is_numchar/1, S) of -% [] -> 0; -% F -> list_to_integer(lists:flatten(string:pad(F, 18, trailing, $0))) -% end. -% +-spec read(Format) -> Result + when Format :: string(), + Result :: {ok, Pucks} | {error, Reason}, + Pucks :: integer(), + Reason :: {badarg, Partial :: string(), Rest :: term()} + | {incomplete, Partial :: string(), Rest :: binary()} + | format. +%% @doc +%% Convery any valid string formatted representation and output a value in pucks. +%% This routine can fail in the special case of `ch' style formatting with a single +%% comma and/or a single period in it, as this can trigger misinterpretation as `us' +%% style. When in doubt, always call `read/2' with a style specified. + +read([$木 | Rest]) -> + read_w_gajus(Rest, []); +read([$本 | Rest]) -> + read_w_pucks(Rest, []); +read([C | Rest]) + when C =:= $- orelse + C =:= $− orelse + C =:= $- -> + case read(Rest) of + {ok, Pucks} -> {ok, Pucks * -1}; + Error -> Error + end; +read([C | Rest]) + when C =:= 32 orelse % ASCII space + C =:= 12288 orelse % full-width space + C =:= $\t orelse + C =:= $\r orelse + C =:= $\n -> + read(Rest); +read(_) -> + io:format("Barfing~n"), + {error, format}. + +read_w_gajus([C | Rest], A) when $0 =< C andalso C =< $9 -> + read_w_gajus(Rest, [C | A]); +read_w_gajus([C | Rest], A) when $0 =< C andalso C =< $9 -> + NumC = C - $0 + $0, + read_w_gajus(Rest, [NumC | A]); +read_w_gajus([$, | Rest], A) -> + read_w_gajus(Rest, A); +read_w_gajus([$_ | Rest], A) -> + read_w_gajus(Rest, A); +read_w_gajus([$. | Rest], A) -> + case read_w_pucks(Rest, []) of + {ok, P} -> + G = list_to_integer(lists:reverse(A)) * one_gaju(), + {ok, G + P}; + Error -> + Error + end; +read_w_gajus([], A) -> + G = list_to_integer(lists:reverse(A)) * one_gaju(), + {ok, G}; +read_w_gajus([C, 32 | Rest], A) -> + read_b_gajus(Rest, [{C, A}]); +read_w_gajus(_, _) -> + io:format("Derping~n"), + {error, format}. + +read_w_pucks([C | Rest], A) when $0 =< C andalso C =< $9 -> + read_w_pucks(Rest, [C | A]); +read_w_pucks([C | Rest], A) when $0 =< C andalso C =< $9 -> + NumC = C - $0 + $0, + read_w_pucks(Rest, [NumC | A]); +read_w_pucks([$, | Rest], A) -> + read_w_pucks(Rest, A); +read_w_pucks([$_ | Rest], A) -> + read_w_pucks(Rest, A); +read_w_pucks([], A) -> + Padded = lists:flatten(string:pad(lists:reverse(A), 18, trailing, $0)), + {ok, list_to_integer(Padded)}. + +read_b_gajus(_, _) -> + {error, nyi}. + + %is_numchar(C) -> $0 =< C andalso C =< $9. % %read_jp([$-, Format]) ->