This commit is contained in:
Craig Everett 2025-12-20 01:50:15 +09:00
parent b219d0f784
commit 23137a677e

View File

@ -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 $ =< C andalso C =< $ ->
NumC = C - $ + $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 $ =< C andalso C =< $ ->
NumC = C - $ + $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]) ->