From 2f93c4d5036efb5b4c9e740b6013712c326a0c3a Mon Sep 17 00:00:00 2001 From: Craig Everett Date: Mon, 22 Dec 2025 11:14:13 +0900 Subject: [PATCH] Fix docs --- src/hz_format.erl | 252 ++++++++++++++++++++++++++++++---------------- 1 file changed, 163 insertions(+), 89 deletions(-) diff --git a/src/hz_format.erl b/src/hz_format.erl index cbce80a..d99acd8 100644 --- a/src/hz_format.erl +++ b/src/hz_format.erl @@ -26,8 +26,10 @@ -copyright("Craig Everett "). -license("GPL-3.0-or-later"). --export([amount/1, amount/2, amount/3, amount/4, +-export([amount/1, amount/2, amount/3, + approx_amount/2, approx_amount/3, read/1, + one/1, mark/1, price_to_string/1, string_to_price/1]). -spec amount(Pucks) -> Formatted @@ -35,6 +37,19 @@ Formatted :: string(). %% @doc %% A convenience formatting function. +%% ``` +%% hz_format:amount(1) -> +%% 木0.000,000,000,000,000,001 +%% +%% hz_format:amount(5000) -> +%% 木0.000,000,000,000,005 +%% +%% hz_format:amount(5000000000000000000) -> +%% 木5 +%% +%% hz_format:amount(500000123000000000000000) -> +%% 木500,000.123 +%% ''' %% @equiv amount(us, Pucks). amount(Pucks) -> @@ -49,6 +64,25 @@ amount(Pucks) -> Formatted :: string(). %% @doc %% A money formatting function. +%% ``` +%% hz_format:amount(us, 100500040123000000000000000) -> +%% 木100,500,040.123 +%% +%% hz_format:amount(jp, 100500040123000000000000000) -> +%% 1億50万40木 12京3000兆本 +%% +%% hz_format:amount(metric, 100500040123000000000000000) -> +%% 木100m 500k 40 G 123p P +%% +%% hz_format:amount(legacy, 100500040123000000000000000) -> +%% 木100m 500k 40 G 123q P +%% +%% hz_format:amount({$_, 3}, 100500040123000000000000000) -> +%% 木100_500_040.123 +%% +%% hz_format:amount({$_, 4}, 100500040123000000000000000) -> +%% 木1_0050_0040.123 +%% ''' %% @equiv amount(gaju, Style, Pucks). amount(Style, Pucks) -> @@ -64,6 +98,31 @@ amount(Style, Pucks) -> Formatted :: string(). %% @doc %% A simplified format function covering the most common formats desired. +%% ``` +%% hz_format:amount(gaju, us, 100500040123000004500000000) -> +%% 木100,500,040.123,000,004,5 +%% +%% hz_format:amount(puck, us, 100500040123000004500000000) -> +%% 本100,500,040,123,000,004,500,000,000 +%% +%% hz_format:amount(gaju, jp, 100500040123000004500000000) -> +%% 1億50万40木 12京3000兆45億本 +%% +%% hz_format:amount(puck, jp, 100500040123000004500000000) -> +%% 100秭5000垓4012京3000兆45億本 +%% +%% hz_format:amount(gaju, metric, 100500040123000004500000000) -> +%% 木100m 500k 40 G 123p 4g 500m P +%% +%% hz_format:amount(puck, metric, 100500040123000004500000000) -> +%% 本100y 500z 40e 123p 4g 500m P +%% +%% hz_format:amount(gaju, legacy, 100500040123000004500000000) -> +%% 木100m 500k 40 G 123q 4b 500m P +%% +%% hz_format:amount(puck, legacy, 100500040123000004500000000) -> +%% 本100y 500z 40e 123q 4b 500m P +%% ''' amount(gaju, us, Pucks) -> western($,, $., 3, all, Pucks); @@ -81,66 +140,51 @@ amount(puck, {Separator, Span}, Pucks) -> western(Separator, Span, Pucks). --spec amount(Unit, Style, Precision, Pucks) -> Serialized - when Unit :: gaju | puck, - Style :: us | jp | metric | legacy | {Separator, Span}, + +-spec approx_amount(Precision, Pucks) -> Serialized + when Precision :: all | 0..18, + Pucks :: integer(), + Serialized :: string(). +%% A formatter for decimal notation which permits a precision +%% value to be applied to the puck side of the format. +%% @equiv approx_amount(us, Precision, Pucks). +%% ``` +%% hz_format:approx_amount(3, 100500040123000004500000001) -> +%% 木100,500,040.123... +%% +%% hz_format:approx_amount(13, 100500040123000004500000001) -> +%% 木100,500,040.123,000,004,5... +%% +%% hz_format:approx_amount(all, 100500040123000004500000001) -> +%% 木100,500,040.123,000,004,500,000,001 +%% ''' + +approx_amount(Precision, Pucks) -> + approx_amount(us, Precision, Pucks). + + +-spec approx_amount(Style, Precision, Pucks) -> Serialized + when Style :: us | {Separator, Span}, Precision :: all | 0..18, Separator :: $, | $_, Span :: 3 | 4, Pucks :: integer(), Serialized :: string(). %% @doc -%% A flexible, if annoyingly complex, formatting function. -%% +%% A formatter for decimal notation which permits a precision +%% value to be applied to the puck side of the format. %% ``` -%% amount(gaju, us, 3, 123456789123456789123456789) -> -%% "木123,456,789.123...". +%% hz_format:approx_amount({$_, 3}, 3, 100500040123000004500000001) -> +%% 木100_500_040.123... %% -%% amount(gaju, us, 3, 123456789123000000000000000) -> -%% "木123,456,789.123". -%% -%% amount(gaju, {$,, 3}, 3, 123456789123456789123456789) -> -%% "木123,456,789.123...". -%% -%% amount(gaju, {$,, 3}, 6, 123456789123000000000000000) -> -%% "木123,456,789.123" -%% -%% amount(gaju, {$_, 4}, 10, 123456789123456789123456789) -> -%% "木1_2345_6789.1234_5678_91..." -%% -%% amount(gaju, jp, 3, 123456789123456789123456789) -> -%% "1億2345万6789木 12京3000兆本" -%% -%% amount(gaju, jp, 6, 123456789123456789123456789) -> -%% "1億2345万6789木 12京3456兆本" -%% -%% amount(gaju, jp, 0, 123456789123456789123456789) -> -%% "1億2345万6789木" -%% -%% amount(puck, jp, all, 123456789123456789123456789) -> -%% "123秭4567垓8912京3456兆7891億2345万6789本" +%% hz_format:approx_amount({$_, 4}, 12, 100500040123000004500000001) -> +%% 木1_0050_0040.1230_0000_45... %% ''' -amount(gaju, us, Precision, Pucks) -> +approx_amount(us, Precision, Pucks) -> western($,, $., 3, Precision, Pucks); -amount(gaju, jp, Precision, Pucks) -> - jp(gaju, Precision, Pucks); -amount(gaju, metric, Precision, Pucks) -> - bestern(gaju, ranks(metric), Precision, Pucks); -amount(gaju, legacy, Precision, Pucks) -> - bestern(gaju, ranks(heresy), Precision, Pucks); -amount(gaju, {Separator, Span}, Precision, Pucks) -> - western(Separator, $., Span, Precision, Pucks); -amount(puck, us, _, Pucks) -> - western($,, 3, Pucks); -amount(puck, jp, _, Pucks) -> - jp(puck, all, Pucks); -amount(puck, metric, _, Pucks) -> - bestern(puck, ranks(metric), all, Pucks); -amount(puck, legacy, _, Pucks) -> - bestern(puck, ranks(heresy), all, Pucks); -amount(puck, {Separator, Span}, _, Pucks) -> - western(Separator, Span, Pucks). +approx_amount({Separator, Span}, Precision, Pucks) -> + western(Separator, $., Span, Precision, Pucks). western(Separator, Span, Pucks) when Pucks >= 0 -> @@ -150,7 +194,7 @@ western(Separator, Span, Pucks) when Pucks < 0 -> western2(Separator, Span, Pucks) -> P = lists:reverse(integer_to_list(Pucks)), - [puck_mark() | separate(Separator, Span, P)]. + [mark(puck) | separate(Separator, Span, P)]. western(Separator, Break, Span, Precision, Pucks) when Pucks >= 0 -> @@ -160,30 +204,30 @@ western(Separator, Break, Span, Precision, Pucks) when Pucks < 0 -> western2(Separator, _, Span, 0, Pucks) -> - G = lists:reverse(integer_to_list(Pucks div one_gaju())), - [gaju_mark() | separate(Separator, Span, G)]; + G = lists:reverse(integer_to_list(Pucks div one(gaju))), + [mark(gaju) | separate(Separator, Span, G)]; western2(Separator, Break, Span, Precision, Pucks) -> SP = integer_to_list(Pucks), Length = length(SP), Over18 = Length > 18, - NoPucks = (Pucks rem one_gaju()) =:= 0, + NoPucks = (Pucks rem one(gaju)) =:= 0, case {Over18, NoPucks} of {true, true} -> Gs = lists:reverse(lists:sublist(SP, Length - 18)), - [gaju_mark() | separate(Separator, Span, Gs)]; + [mark(gaju) | separate(Separator, Span, Gs)]; {true, false} -> {PChars, GChars} = lists:split(18, lists:reverse(SP)), - H = [gaju_mark() | separate(Separator, Span, GChars)], + H = [mark(gaju) | separate(Separator, Span, GChars)], {P, E} = decimal_pucks(Precision, lists:reverse(PChars)), T = lists:reverse(separate(Separator, Span, P)), lists:flatten([H, Break, T, E]); {false, true} -> - [gaju_mark(), $0]; + [mark(gaju), $0]; {false, false} -> PChars = lists:flatten(string:pad(SP, 18, leading, $0)), {P, E} = decimal_pucks(Precision, PChars), T = lists:reverse(separate(Separator, Span, P)), - lists:flatten([gaju_mark(), $0, Break, T, E]) + lists:flatten([mark(gaju), $0, Break, T, E]) end. decimal_pucks(all, PChars) -> @@ -212,13 +256,13 @@ separate(S, P, N, [H | T], A) -> bestern(gaju, Ranks, Precision, Pucks) when Pucks >= 0 -> - [gaju_mark(), bestern2(gaju, Ranks, 3, Precision, Pucks)]; + [mark(gaju), bestern2(gaju, Ranks, 3, Precision, Pucks)]; bestern(gaju, Ranks, Precision, Pucks) when Pucks < 0 -> - [$-, gaju_mark(), bestern2(gaju, Ranks, 3, Precision, Pucks * -1)]; + [$-, mark(gaju), bestern2(gaju, Ranks, 3, Precision, Pucks * -1)]; bestern(puck, Ranks, Precision, Pucks) when Pucks >= 0 -> - [puck_mark(), bestern2(puck, Ranks, 3, Precision, Pucks)]; + [mark(puck), bestern2(puck, Ranks, 3, Precision, Pucks)]; bestern(puck, Ranks, Precision, Pucks) when Pucks < 0 -> - [$-, puck_mark(), bestern2(puck, Ranks, 3, Precision, Pucks * -1)]. + [$-, mark(puck), bestern2(puck, Ranks, 3, Precision, Pucks * -1)]. jp(Unit, Precision, Pucks) when Pucks >= 0 -> bestern2(Unit, ranks(jp), 4, Precision, Pucks); @@ -226,24 +270,24 @@ jp(Unit, Precision, Pucks) when Pucks < 0 -> [$-, bestern2(Unit, ranks(jp), 4, Precision, Pucks * -1)]. bestern2(gaju, Ranks, Span, 0, Pucks) -> - G = lists:reverse(integer_to_list(Pucks div one_gaju())), + G = lists:reverse(integer_to_list(Pucks div one(gaju))), case Span of 3 -> period("G", Ranks, G); - 4 -> myriad(gaju_mark(), Ranks, G) + 4 -> myriad(mark(gaju), Ranks, G) end; bestern2(gaju, Ranks, Span, all, Pucks) -> - P = lists:flatten(string:pad(integer_to_list(Pucks rem one_gaju()), 18, leading, $0)), + P = lists:flatten(string:pad(integer_to_list(Pucks rem one(gaju)), 18, leading, $0)), Zilch = lists:all(fun(C) -> C =:= $0 end, P), {H, T} = case {Span, Zilch} of {3, false} -> {bestern2(gaju, Ranks, 3, 0, Pucks), period("P", Ranks, lists:reverse(P))}; - {4, false} -> {jp(gaju, 0, Pucks), myriad(puck_mark(), Ranks, lists:reverse(P))}; + {4, false} -> {jp(gaju, 0, Pucks), myriad(mark(puck), Ranks, lists:reverse(P))}; {3, true} -> {bestern2(gaju, Ranks, 3, 0, Pucks), ""}; {4, true} -> {jp(gaju, 0, Pucks), ""} end, lists:flatten([H, " ", T]); bestern2(gaju, Ranks, Span, Precision, Pucks) -> - P = lists:flatten(string:pad(integer_to_list(Pucks rem one_gaju()), 18, leading, $0)), + P = lists:flatten(string:pad(integer_to_list(Pucks rem one(gaju)), 18, leading, $0)), H = case Span of 3 -> bestern2(gaju, Ranks, 3, 0, Pucks); @@ -259,7 +303,7 @@ bestern2(gaju, Ranks, Span, Precision, Pucks) -> false -> case Span of 3 -> period("P", Ranks, PuckingString); - 4 -> myriad(puck_mark(), Ranks, PuckingString) + 4 -> myriad(mark(puck), Ranks, PuckingString) end; true -> "" @@ -274,12 +318,12 @@ bestern2(puck, Ranks, Span, all, Pucks) -> false -> case Span of 3 -> period("P", Ranks, P); - 4 -> myriad(puck_mark(), Ranks, P) + 4 -> myriad(mark(puck), Ranks, P) end; true -> case Span of 3 -> [$0, " P"]; - 4 -> [$0, puck_mark()] + 4 -> [$0, mark(puck)] end end; bestern2(puck, Ranks, Span, Precision, Pucks) -> @@ -289,7 +333,7 @@ bestern2(puck, Ranks, Span, Precision, Pucks) -> true -> case Span of 3 -> [$0, " P"]; - 4 -> [$0, puck_mark()] + 4 -> [$0, mark(puck)] end; false -> PucksToGive = lists:sublist(P, Digits), @@ -298,12 +342,12 @@ bestern2(puck, Ranks, Span, Precision, Pucks) -> false -> case Span of 3 -> period("P", Ranks, PuckingString); - 4 -> myriad(puck_mark(), Ranks, PuckingString) + 4 -> myriad(mark(puck), Ranks, PuckingString) end; true -> case Span of 3 -> [$0, " P"]; - 4 -> [$0, puck_mark()] + 4 -> [$0, mark(puck)] end end end. @@ -418,11 +462,11 @@ ranks(heresy) -> ["k ", "m ", "b ", "t ", "q ", "e ", "z ", "y ", "r ", "Q "]. -gaju_mark() -> $木. +mark(gaju) -> $木; +mark(puck) -> $本. -puck_mark() -> $本. - -one_gaju() -> 1_000_000_000_000_000_000. +one(gaju) -> 1_000_000_000_000_000_000; +one(puck) -> 1. -spec read(Format) -> Result @@ -430,10 +474,26 @@ one_gaju() -> 1_000_000_000_000_000_000. Result :: {ok, Pucks} | error, Pucks :: integer(). %% @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. +%% Convert any valid string formatted representation and output a value in pucks. +%% NOTE: This function does not accept approximated values. +%% ``` +%% 1> hz_format:read("木100,500,040.123,000,004,5"). +%% {ok,100500040123000004500000000} +%% 2> hz_format:read("本100,500,040,123,000,004,500,000,000"). +%% {ok,100500040123000004500000000} +%% 3> hz_format:read("1億50万40木 12京3000兆45億本"). +%% {ok,100500040123000004500000000} +%% 4> hz_format:read("100秭5000垓4012京3000兆45億本"). +%% {ok,100500040123000004500000000} +%% 5> hz_format:read("木100m 500k 40 G 123p 4g 500m P"). +%% {ok,100500040123000004500000000} +%% 6> hz_format:read("本100y 500z 40e 123p 4g 500m P"). +%% {ok,100500040123000004500000000} +%% 7> hz_format:read("木100m 500k 40 G 123q 4b 500m P"). +%% {ok,100500040123000004500000000} +%% 8> hz_format:read("本100y 500z 40e 123q 4b 500m P"). +%% {ok,100500040123000004500000000} +%% ''' read([$木 | Rest]) -> read_w_gajus(Rest, []); @@ -459,6 +519,8 @@ read([C | Rest]) when $0 =< C andalso C =< $9 -> read([C | Rest]) when $0 =< C andalso C =< $9 -> NumC = C - $0 + $0, read(Rest, [NumC], []); +read(String) when is_binary(String) -> + read(binary_to_list(String)); read(_) -> error. @@ -474,13 +536,13 @@ 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(), + 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(), + G = list_to_integer(lists:reverse(A)) * one(gaju), {ok, G}; read_w_gajus([C, 32 | Rest], A) -> read(Rest, [], [{C, A}]); @@ -488,7 +550,10 @@ read_w_gajus([32, $G, 32 | Rest], A) -> read(Rest, [], [{$G, A}], []); read_w_gajus([32, $G], A) -> calc([{$G, A}], []); -read_w_gajus(_, _) -> +read_w_gajus([32, $P], A) -> + calc([], [{$P, A}]); +read_w_gajus(A, B) -> + io:format("A: ~ts, B: ~p~n", [A, B]), error. read_w_pucks([C | Rest], A) when $0 =< C andalso C =< $9 -> @@ -500,6 +565,10 @@ read_w_pucks([$, | Rest], A) -> read_w_pucks(Rest, A); read_w_pucks([$_ | Rest], A) -> read_w_pucks(Rest, A); +read_w_pucks([C, 32 | Rest], A) -> + read(Rest, [], [], [{C, A}]); +read_w_pucks([32, $P], A) -> + calc([], [{$P, A}]); read_w_pucks([], A) -> Padded = lists:flatten(string:pad(lists:reverse(A), 18, trailing, $0)), {ok, list_to_integer(Padded)}. @@ -514,6 +583,10 @@ read([$木], A, G) -> calc([{$G, A} | G], []); read([$G], A, G) -> calc([{$G, A} | G], []); +read([32, $G], A, G) -> + calc([{$G, A} | G], []); +read([32, $G, 32 | Rest], A, G) -> + read(Rest, [], [{$G, A} | G], []); read([$木, 32 | Rest], A, G) -> read(Rest, [], [{$G, A} | G], []); read([$G, 32 | Rest], A, G) -> @@ -522,6 +595,8 @@ read([$本], A, P) -> calc([], [{$P, A} | P]); read([$P], A, P) -> calc([], [{$P, A} | P]); +read([32, $P], A, P) -> + calc([], [{$P, A} | P]); read([C, 32 | Rest], A, G) -> read(Rest, [], [{C, A} | G]); read([C | Rest], A, G) -> @@ -540,6 +615,8 @@ read([$本], A, G, P) -> calc(G, [{$P, A} | P]); read([$P], A, G, P) -> calc(G, [{$P, A} | P]); +read([32, $P], A, G, P) -> + calc(G, [{$P, A} | P]); read([C, 32 | Rest], A, G, P) -> read(Rest, [], G, [{C, A} | P]); read([C | Rest], A, G, P) -> @@ -564,7 +641,7 @@ calc(U, [{_, []} | S], A) -> calc(U, [{M, Cs} | S], A) -> case magnitude(M) of {ok, J} -> - N = list_to_integer(lists:reverse(Cs)) * J * unit(U), + N = list_to_integer(lists:reverse(Cs)) * J * one(U), calc(U, S, A + N); Error -> Error @@ -572,9 +649,6 @@ calc(U, [{M, Cs} | S], A) -> calc(_, [], A) -> {ok, A}. -unit(gaju) -> one_gaju(); -unit(puck) -> 1. - magnitude($G) -> {ok, 1}; @@ -607,7 +681,7 @@ rank(_, [], _, _) -> %% in Gajus. Useful for formatting generic output for UI elements price_to_string(Pucks) -> - Gaju = 1_000_000_000_000_000_000, + Gaju = one(gaju), H = integer_to_list(Pucks div Gaju), R = Pucks rem Gaju, case string:strip(lists:flatten(io_lib:format("~18..0w", [R])), right, $0) of