123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302 |
- %%%-------------------------------------------------------------------
- %%% File: erlydtl_filters.erl
- %%% @author Roberto Saccon <rsaccon@gmail.com> [http://rsaccon.com]
- %%% @author Evan Miller <emmiller@gmail.com>
- %%% @copyright 2008 Roberto Saccon, Evan Miller
- %%% @doc
- %%% Template filters
- %%% @end
- %%%
- %%% The MIT License
- %%%
- %%% Copyright (c) 2007 Roberto Saccon, Evan Miller
- %%%
- %%% Permission is hereby granted, free of charge, to any person obtaining a copy
- %%% of this software and associated documentation files (the "Software"), to deal
- %%% in the Software without restriction, including without limitation the rights
- %%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- %%% copies of the Software, and to permit persons to whom the Software is
- %%% furnished to do so, subject to the following conditions:
- %%%
- %%% The above copyright notice and this permission notice shall be included in
- %%% all copies or substantial portions of the Software.
- %%%
- %%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- %%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- %%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- %%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- %%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- %%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- %%% THE SOFTWARE.
- %%%
- %%% @since 2007-11-11 by Roberto Saccon, Evan Miller
- %%%-------------------------------------------------------------------
- -module(erlydtl_filters).
- -author('rsaccon@gmail.com').
- -author('emmiller@gmail.com').
- -author('drew dot gulino at google dot com').
-
- -ifdef(TEST).
- -undef(TEST).
- -endif.
- -define(TEST,"").
- %-define(NOTEST,1).
- -define(NODEBUG,1).
- -include_lib("eunit/include/eunit.hrl").
-
- -ifdef(TEST).
- -export([cast_to_float/1,cast_to_integer/1,stringformat_io/7,round/2,unjoin/2,addDefaultURI/1]).
- -endif.
-
-
- -export([add/2,
- addslashes/1,
- capfirst/1,
- center/2,
- cut/2,
- date/1,
- date/2,
- default/2,
- default_if_none/2,
- dictsort/2,
- dictsortreversed/2,
- divisibleby/2,
- %escape/, - implemented in erlydtl_compiler
- escapejs/1,
- filesizeformat/1,
- first/1,
- fix_ampersands/1,
- floatformat/1,
- floatformat/2,
- force_escape/1,
- format_integer/1,
- format_number/1,
- get_digit/2,
- iriencode/1,
- join/2,
- last/1,
- length/1,
- length_is/2,
- linebreaks/1,
- linebreaksbr/1,
- linenumbers/1,
- ljust/2,
- lower/1,
- make_list/1,
- phone2numeric/1,
- pluralize/1,
- pluralize/2,
- pprint/1,
- random/1,
- random_num/1,
- random_range/1,
- removetags/2,
- rjust/2,
- %safe/, - implemented in erlydtl_compiler
- %safeseq/, - implemented in erlydtl_compiler
- slice/2,
- slugify/1,
- stringformat/2,
- striptags/1,
- time/1,
- time/2,
- timesince/1,
- timesince/2,
- timeuntil/1,
- timeuntil/2,
- title/1,
- truncatechars/2,
- truncatewords/2,
- truncatewords_html/2,
- unordered_list/1,
- upper/1,
- urlencode/1,
- urlencode/2,
- urlize/1,
- urlize/2,
- urlizetrunc/2,
- wordcount/1,
- wordwrap/2,
- yesno/2]).
-
- -define(NO_ENCODE(C), ((C >= $a andalso C =< $z) orelse
- (C >= $A andalso C =< $Z) orelse
- (C >= $0 andalso C =< $9) orelse
- (C =:= $\. orelse C =:= $-
- orelse C =:= $~ orelse C =:= $_))).
- -define(NO_IRI_ENCODE(C), (?NO_ENCODE(C) orelse (
- C =:= $/ orelse
- C =:= $# orelse
- C =:= $[ orelse
- C =:= $] orelse
- C =:= $= orelse
- C =:= $: orelse
- C =:= $; orelse
- C =:= $$ orelse
- C =:= $& orelse
- C =:= $( orelse
- C =:= $) orelse
- C =:= $+ orelse
- C =:= $, orelse
- C =:= $! orelse
- C =:= $? orelse
- C =:= $* orelse
- C =:= $@ orelse
- C =:= $' orelse
- C =:= $~))).
-
- -define(KILOBYTE, 1024).
- -define(MEGABYTE, (1024 * ?KILOBYTE)).
- -define(GIGABYTE, (1024 * ?MEGABYTE)).
- -define(SECONDS_PER_MINUTE, 60).
- -define(SECONDS_PER_HOUR, (60 * ?SECONDS_PER_MINUTE)).
- -define(SECONDS_PER_DAY, (24 * ?SECONDS_PER_HOUR)).
- -define(SECONDS_PER_WEEK, (7 * ?SECONDS_PER_DAY)).
- -define(SECONDS_PER_MONTH, (30 * ?SECONDS_PER_DAY)).
- -define(SECONDS_PER_YEAR, (365 * ?SECONDS_PER_DAY)).
-
- %% @doc Adds to values
- add(LHS, RHS) when is_number(LHS), is_number(RHS) ->
- LHS + RHS;
- add(LHS, RHS) when is_binary(LHS) ->
- add(unicode:characters_to_list(LHS), RHS);
- add(LHS, RHS) when is_binary(RHS) ->
- add(LHS, unicode:characters_to_list(RHS));
- add(LHS, RHS) when is_list(LHS), is_list(RHS) ->
- case {to_numeric(LHS), to_numeric(RHS)} of
- {{number, LHSNum}, {number, RHSNum}} ->
- LHSNum + RHSNum;
- _ ->
- LHS ++ RHS
- end;
- add(LHS, RHS) when is_list(LHS), is_number(RHS) ->
- case to_numeric(LHS) of
- {number, LHSNum} ->
- LHSNum + RHS;
- _ ->
- LHS ++ to_string(RHS)
- end;
- add(LHS, RHS) when is_number(LHS), is_list(RHS) ->
- case to_numeric(RHS) of
- {number, RHSNum} ->
- LHS + RHSNum;
- _ ->
- to_string(LHS) ++ RHS
- end.
- to_string(Num) when is_integer(Num) ->
- integer_to_list(Num);
- to_string(Num) when is_float(Num) ->
- float_to_list(Num).
- to_numeric(List) ->
- try
- {number, list_to_integer(List)}
- catch
- error:badarg ->
- try
- {number, list_to_float(List)}
- catch
- error:badarg ->
- undefined
- end
- end.
-
- %% @doc Adds slashes before quotes.
- addslashes(Input) when is_binary(Input) ->
- addslashes(unicode:characters_to_list(Input));
- addslashes(Input) when is_list(Input) ->
- addslashes(Input, []).
-
- %% @doc Capitalizes the first character of the value.
- capfirst([H|T]) when H >= $a andalso H =< $z ->
- [H + $A - $a | T];
- capfirst(Other) when is_list(Other) ->
- Other;
- capfirst(<<Byte:8/integer, Binary/binary>>) when Byte >= $a andalso Byte =< $z ->
- [(Byte + $A - $a)|unicode:characters_to_list(Binary)];
- capfirst(Other) when is_binary(Other) ->
- Other.
-
- %% @doc Centers the value in a field of a given width.
- center(Input, Number) when is_binary(Input) ->
- unicode:characters_to_binary(center(unicode:characters_to_list(Input), Number));
- center(Input, Number) when is_list(Input) ->
- string:centre(Input, Number).
-
- %% @doc Removes all values of arg from the given string.
- cut(Input, Arg) when is_binary(Arg) ->
- cut(Input, unicode:characters_to_list(Arg));
- cut(Input, Arg) when is_binary(Input) ->
- cut(unicode:characters_to_list(Input), Arg);
- cut(Input, [Char]) when is_list(Input) ->
- cut(Input, Char, []).
-
- %% @doc Formats a date according to the default format.
- date(Input) ->
- date(Input, "F j, Y").
- %% @doc Formats a date according to the given format.
- date(Input, FormatStr)
- when is_tuple(Input)
- andalso (size(Input) == 2 orelse size(Input) == 3) ->
- erlydtl_dateformat:format(Input, FormatStr);
- date(Input, _FormatStr) ->
- io:format("Unexpected date parameter: ~p~n", [Input]),
- "".
- %% @doc If value evaluates to `false', use given default. Otherwise, use the value.
- default(Input, Default) ->
- case erlydtl_runtime:is_false(Input) of
- true -> Default;
- false -> Input
- end.
- %% @doc If (and only if) value is `undefined', use given default. Otherwise, use the value.
- default_if_none(undefined, Default) ->
- Default;
- default_if_none(Input, _) ->
- Input.
- %% @doc Takes a list of dictionaries or proplists and returns that list sorted by the key given in the argument.
- dictsort(DictList, Key) when is_binary(Key) ->
- dictsort(DictList, [binary_to_atom(B,latin1) ||
- B <- binary:split(Key,<<".">>)]);
- dictsort(DictList, Key) ->
- case lists:all(
- fun(Dict) ->
- erlydtl_runtime:find_deep_value(Key, Dict) /= undefined
- end, DictList) of
- true ->
- lists:sort(
- fun(K1,K2) ->
- erlydtl_runtime:find_deep_value(Key,K1) =<
- erlydtl_runtime:find_deep_value(Key,K2)
- end, DictList);
- false -> error
- end.
- %% @doc Same as dictsort, but the list is reversed.
- dictsortreversed(DictList, Key) ->
- lists:reverse(dictsort(DictList, Key)).
- %% @doc Returns `true' if the value is divisible by the argument.
- divisibleby(Input, Divisor) when is_binary(Input) ->
- divisibleby(unicode:characters_to_list(Input), Divisor);
- divisibleby(Input, Divisor) when is_list(Input) ->
- divisibleby(list_to_integer(Input), Divisor);
- divisibleby(Input, Divisor) when is_binary(Divisor) ->
- divisibleby(Input, unicode:characters_to_list(Divisor));
- divisibleby(Input, Divisor) when is_list(Divisor) ->
- divisibleby(Input, list_to_integer(Divisor));
- divisibleby(Input, Divisor) when is_integer(Input), is_integer(Divisor) ->
- Input rem Divisor =:= 0.
- %% @doc Escapes characters for use in JavaScript strings.
- escapejs(Input) when is_binary(Input) ->
- unicode:characters_to_binary(escapejs(unicode:characters_to_list(Input)));
- escapejs(Input) when is_list(Input) ->
- escapejs(Input, []).
- %% @doc Format the value like a human-readable file size.
- filesizeformat(Input) when is_binary(Input) ->
- filesizeformat(unicode:characters_to_list(Input));
- filesizeformat(Input) when is_list(Input) ->
- filesizeformat(list_to_integer(Input));
- filesizeformat(Bytes) when is_integer(Bytes), Bytes >= ?GIGABYTE->
- filesizeformat(Bytes / ?GIGABYTE, "GB");
- filesizeformat(Bytes) when is_integer(Bytes), Bytes >= ?MEGABYTE ->
- filesizeformat(Bytes / ?MEGABYTE, "MB");
- filesizeformat(Bytes) when is_integer(Bytes), Bytes >= ?KILOBYTE ->
- filesizeformat(Bytes / ?KILOBYTE, "KB");
- filesizeformat(Bytes) when is_integer(Bytes) ->
- integer_to_list(Bytes) ++ " bytes".
- %% @doc Returns the first item in a list.
- first([First|_Rest]) ->
- [First];
- first(<<First, _/binary>>) ->
- <<First>>.
- %% @doc Replaces ampersands with & entities.
- fix_ampersands(Input) when is_binary(Input) ->
- fix_ampersands(Input, 0);
- fix_ampersands(Input) when is_list(Input) ->
- fix_ampersands(Input, []).
- %% @doc When used without an argument, rounds a floating-point number to one decimal place
- %% -- but only if there's a decimal part to be displayed
- floatformat(Number) ->
- floatformat(Number, []).
- floatformat(Number, Place)
- when is_number(Number); is_binary(Number); is_list(Number) ->
- floatformat_io(cast_to_float(Number), cast_to_integer(Place));
- floatformat(_, _) -> "".
- floatformat_io(Number, []) ->
- floatformat_io(Number, -1);
- floatformat_io(Number, 0) ->
- hd(io_lib:format("~B", [erlang:round(Number)]));
- floatformat_io(Number, Precision) when Precision > 0 ->
- hd(io_lib:format("~.*f",[Precision, Number]));
- floatformat_io(Number, Precision) when Precision < 0 ->
- Round = erlang:round(Number),
- RoundPrecision = round(Number, -Precision),
- if RoundPrecision == Round ->
- floatformat_io(Round, 0);
- true ->
- floatformat_io(RoundPrecision, -Precision)
- end.
- round(Number, Precision) ->
- P = math:pow(10, Precision),
- erlang:round(Number * P) / P.
- %% @doc Applies HTML escaping to a string.
- force_escape(Input) when is_list(Input) ->
- escape(Input, []);
- force_escape(Input) when is_binary(Input) ->
- escape(Input, 0);
- force_escape(Input) ->
- Input.
- format_integer(Input) when is_integer(Input) ->
- integer_to_list(Input);
- format_integer(Input) ->
- Input.
- format_number(Input) when is_integer(Input) ->
- integer_to_list(Input);
- format_number(Input) when is_float(Input) ->
- io_lib:format("~p", [Input]);
- format_number(Input) when is_function(Input, 0) ->
- format_number(Input());
- format_number(Input) ->
- Input.
- %% @doc Given a whole number, returns the requested digit, where 1 is the right-most digit.
- get_digit(Input, Digit) when is_binary(Input) ->
- get_digit(unicode:characters_to_list(Input), Digit);
- get_digit(Input, Digit) when is_integer(Input) ->
- get_digit(integer_to_list(Input), Digit);
- get_digit(Input, Digit) when is_binary(Digit) ->
- get_digit(Input, unicode:characters_to_list(Digit));
- get_digit(Input, Digit) when is_list(Digit) ->
- get_digit(Input, list_to_integer(Digit));
- get_digit(Input, Digit) when Digit > erlang:length(Input) ->
- 0;
- get_digit(Input, Digit) when Digit > 0 ->
- lists:nth(Digit, lists:reverse(Input)) - $0;
- get_digit(Input, _) ->
- Input.
- iriencode(Input) ->
- iriencode(unicode:characters_to_list(Input), []).
- %% @doc Joins a list with a given separator.
- join(Input, Separator) when is_list(Input) ->
- join_io(Input, Separator).
- %% @doc Returns the last item in a list.
- last(Input) when is_binary(Input) ->
- case size(Input) of
- 0 -> Input;
- N ->
- Offset = N - 1,
- <<_:Offset/binary, Byte/binary>> = Input,
- Byte
- end;
- last(Input) when is_list(Input) ->
- [lists:last(Input)].
- %% @doc Returns the length of the value.
- length(Input) when is_list(Input) ->
- integer_to_list(erlang:length(Input));
- length(Input) when is_binary(Input) ->
- integer_to_list(size(Input)).
- %% @doc Returns True iff the value's length is the argument.
- length_is(Input, Number) when is_list(Input), is_integer(Number) ->
- length_is(Input, integer_to_list(Number));
- length_is(Input, Number) when is_list(Input), is_list(Number) ->
- ?MODULE:length(Input) =:= Number.
- %% @doc Replaces line breaks in plain text with appropriate HTML
- linebreaks(Input) when is_binary(Input) ->
- linebreaks(unicode:characters_to_list(Input),[]);
- linebreaks(Input) ->
- linebreaks(Input,[]).
- linebreaks([],Acc) ->
- "<p>" ++ lists:reverse(Acc) ++ "</p>";
- linebreaks([$\n|T], ">p<"++_ = Acc) ->
- linebreaks(T, Acc);
- linebreaks([$\r|T], ">p<"++_ = Acc) ->
- linebreaks(T, Acc);
- linebreaks([$\n, $\n|T],Acc) ->
- linebreaks(T, lists:reverse("</p><p>", Acc));
- linebreaks([$\r, $\n, $\r, $\n|T],Acc) ->
- linebreaks(T, lists:reverse("</p><p>", Acc));
- linebreaks([$\r, $\n|T], Acc) ->
- linebreaks(T, lists:reverse("<br />", Acc));
- linebreaks([$\n|T], Acc) ->
- linebreaks(T, lists:reverse("<br />", Acc));
- linebreaks([C|T], Acc) ->
- linebreaks(T, [C|Acc]).
- %% @doc Converts all newlines to HTML line breaks.
- linebreaksbr(Input) when is_binary(Input) ->
- linebreaksbr(Input, 0);
- linebreaksbr(Input) ->
- linebreaksbr(Input, []).
- %% @doc Displays text with line numbers.
- linenumbers(Input) when is_binary(Input) ->
- linenumbers(unicode:characters_to_list(Input));
- linenumbers(Input) when is_list(Input) ->
- linenumbers_io(Input, [], 1).
- linenumbers_io([], Acc, _) ->
- lists:reverse(Acc);
- linenumbers_io(Input, [], LineNumber) ->
- linenumbers_io(Input, lists:reverse(integer_to_list(LineNumber)++". "), LineNumber + 1);
- linenumbers_io("\n"++Rest, Acc, LineNumber) ->
- linenumbers_io(Rest, lists:reverse("\n" ++ integer_to_list(LineNumber) ++ ". ", Acc), LineNumber + 1);
- linenumbers_io([H|T], Acc, LineNumber) ->
- linenumbers_io(T, [H|Acc], LineNumber).
- %% @doc Left-aligns the value in a field of a given width.
- ljust(Input, Number) when is_binary(Input) ->
- unicode:characters_to_binary(ljust(unicode:characters_to_list(Input), Number));
- ljust(Input, Number) when is_list(Input) ->
- string:left(Input, Number).
- %% @doc Converts a string into all lowercase.
- lower(Input) when is_binary(Input) ->
- lower(Input, 0);
- lower(Input) ->
- string:to_lower(Input).
- %% @doc Returns the value turned into a list. For an integer, it's a list of digits.
- %% For a string, it's a list of characters.
- %% Added this for DTL compatibility, but since strings are lists in Erlang, no need for this.
- make_list(Input) when is_binary(Input) ->
- make_list(unicode:characters_to_list(Input));
- make_list(Input) ->
- unjoin(Input,"").
- %% @doc Converts a phone number (possibly containing letters) to its numerical equivalent.
- phone2numeric(Input) when is_binary(Input) ->
- phone2numeric(unicode:characters_to_list(Input));
- phone2numeric(Input) when is_list(Input) ->
- phone2numeric(Input, []).
- %% @doc Returns a plural suffix if the value is not 1. By default, this suffix is 's'.
- pluralize(Number, Suffix) when is_binary(Suffix) ->
- pluralize_io(Number, unicode:characters_to_list(Suffix) );
- pluralize(Number, Suffix) when is_list(Suffix) ->
- pluralize_io(Number, Suffix).
- pluralize(Number) ->
- pluralize(Number, "s").
- pluralize_io(Number, Suffix) ->
- [Singular, Plural] =
- case string:tokens(Suffix,",") of
- [P] -> ["", P];
- [S, P|_] -> [S, P]
- end,
- if Number == 1; Number == "1"; Number == <<"1">> -> Singular;
- true -> Plural
- end.
- %% @doc "pretty print" arbitrary data structures. Used for debugging.
- pprint(Input) ->
- io_lib:format("~p",[Input]).
- %% @doc Returns a random item from the given list.
- random(Input) when is_list(Input) ->
- lists:nth(random:uniform(erlang:length(Input)), Input);
- random(_) ->
- "".
- random_num(Value) ->
- random:seed(now()),
- random:uniform(Value).
- %% random tags to be used when using erlydtl in testing
- random_range(Range) ->
- [Start, End] = string:tokens(Range,","),
- %?debugFmt("Start, End: ~p,~p~n",[Start,End]),
- random_range(cast_to_integer(Start),cast_to_integer(End)).
- random_range(Start, End) when End >= Start ->
- %?debugFmt("Input, Start, End: ~p,~p,~p~n",[Input,Start,End]),
- Range = End - Start,
- Rand = random:uniform(Range),
- Num = Rand + Start,
- lists:flatten(io_lib:format("~B",[Num])).
- removetags(Input, Tags) when is_binary(Input) ->
- removetags(unicode:characters_to_list(Input), Tags);
- removetags(Input, Tags) when is_binary(Tags) ->
- removetags(Input, unicode:characters_to_list(Tags));
- removetags(Input, Tags) ->
- TagList = string:tokens(Tags," "),
- TagListString = string:join(TagList,"|"),
- Regex = lists:flatten(io_lib:format("</?(~s)( |\n)?>",[TagListString])),
- Result = re:replace(Input,Regex,"", [global,{return,list}]),
- Result.
- %% @doc Right-aligns the value in a field of a given width.
- rjust(Input, Number) when is_binary(Input) ->
- unicode:characters_to_binary(rjust(unicode:characters_to_list(Input), Number));
- rjust(Input, Number) ->
- string:right(Input, Number).
- %% @doc Returns a slice of the list.
- slice(Input, Index) when is_binary(Input) ->
- erlydtl_slice:slice(unicode:characters_to_list(Input), Index);
- slice(Input, Index) when is_list(Input) ->
- erlydtl_slice:slice(Input, Index).
- %% regex " ^([#0-\s+].)([0-9\*]+)(\.[0-9]+)([diouxXeEfFgGcrs]) " matches ALL of "-10.0f"
- %% ([#0-\s+]?)([0-9\*]+)?(\.?)([0-9]?)([diouxXeEfFgGcrs])
- %% @doc Returns a formatted string
- stringformat(Input, Conversion) when is_binary(Input) ->
- stringformat(unicode:characters_to_list(Input), Conversion);
- stringformat(Input, Conversion) when is_binary(Conversion) ->
- stringformat(Input, unicode:characters_to_list(Conversion));
- stringformat(Input, Conversion) ->
- ParsedConversion = re:replace(Conversion, "([\-#\+ ]?)([0-9\*]+)?(\.?)([0-9]?)([diouxXeEfFgGcrs])", "\\1 ,\\2 ,\\3 ,\\4 ,\\5 ", [{return,list}]),
- ?debugFmt("ParsedConversion: ~p~n", [ParsedConversion]),
- ParsedConversion1 = lists:map(fun(X) -> string:strip(X) end, string:tokens(ParsedConversion, ",")),
- [ConversionFlag, MinFieldWidth, Precision, PrecisionLength, ConversionType] = ParsedConversion1,
- ?debugFmt("ConversionFlag, MinFieldWidth, Precision, PrecisionLength, ConversionType: ~p, ~p, ~p, ~p, ~p ~n", [ConversionFlag, cast_to_integer(MinFieldWidth), Precision, cast_to_integer(PrecisionLength), ConversionType]),
- [String] = stringformat_io(Input, Conversion, ConversionFlag, cast_to_integer(MinFieldWidth), Precision, cast_to_integer(PrecisionLength), ConversionType),
- lists:flatten(String).
- %% @doc
- %% A conversion specifier contains two or more characters and has the following components, which must occur in this order:
- %%
- %% 1. The "%" character, which marks the start of the specifier.
- %% 2. Mapping key (optional), consisting of a parenthesised sequence of characters (for example, (somename)).
- %% 3. Conversion flags (optional), which affect the result of some conversion types.
- %% 4. Minimum field width (optional). If specified as an "*" (asterisk), the actual width is read from the next element of the tuple in values, and the object to convert comes after the minimum field width and optional precision.
- %% 5. Precision (optional), given as a "." (dot) followed by the precision. If specified as "*" (an asterisk), the actual width is read from the next element of the tuple in values, and the value to convert comes after the precision.
- %% 6. Length modifier (optional).
- %% 7. Conversion type.
- stringformat_io(Input, _Conversion, _ConversionFlag, [],
- _Precision, _PrecisionLength, "s") when is_list(Input) ->
- Format = lists:flatten(io_lib:format("~~s", [])),
- io_lib:format(Format, [Input]);
- stringformat_io(Input, _Conversion, ConversionFlag, MinFieldWidth,
- _Precision, _PrecisionLength, "s") when is_list(Input) ->
- %Conversion = [ConversionFlag, MinFieldWidth, Precision, PrecisionLength, ConversionType],
- InputLength = erlang:length(Input),
- case erlang:abs(MinFieldWidth) < InputLength of
- true ->
- MFW = InputLength;
- false ->
- MFW = MinFieldWidth
- end,
- Format = lists:flatten(io_lib:format("~~~s~ps", [ConversionFlag,MFW])),
- io_lib:format(Format, [Input]);
- stringformat_io(Input, _Conversion, _ConversionFlag, MinFieldWidth,
- Precision, PrecisionLength, "f") when Precision == ".", MinFieldWidth == 0 ->
- Conversion1 = lists:concat(["","",Precision,PrecisionLength,"f"]),
- stringformat_io(Input, Conversion1, [], [], Precision, PrecisionLength, "f");
- stringformat_io(Input, Conversion, ConversionFlag, MinFieldWidth,
- Precision, "", "f") when Precision == "." ->
- Format = re:replace(Conversion, "f", "d", [{return, list}] ),
- stringformat_io(Input, Format, ConversionFlag, MinFieldWidth,
- Precision, "", "d");
- stringformat_io(Input, Conversion, _ConversionFlag, _MinFieldWidth,
- _Precision, _PrecisionLength, "f")->
- %Conversion = [ConversionFlag, MinFieldWidth, Precision, PrecisionLength, ConversionType],
- Format = "~" ++ Conversion,
- io_lib:format(Format, [cast_to_float(Input)]);
- stringformat_io(Input, Conversion, _ConversionFlag, _MinFieldWidth,
- [], [], "d")->
- %?debugMsg("plain d"),
- %Conversion = [ConversionFlag, MinFieldWidth, Precision, PrecisionLength, ConversionType],
- Format = "~" ++ re:replace(Conversion, "d", "B", [{return, list}] ),
- io_lib:format(Format, [cast_to_integer(Input)]);
- stringformat_io(Input, _Conversion, "-", MinFieldWidth,
- _Precision, PrecisionLength, "d") when MinFieldWidth > 0 ->
- %Format = "~" ++ re:replace(Conversion, "d", "B", [{return, list}] ),
- DecimalFormat = "~" ++ integer_to_list(PrecisionLength) ++ "..0B",
- Decimal = lists:flatten( io_lib:format(DecimalFormat, [cast_to_integer(Input)]) ),
- SpaceFormat = "~" ++ integer_to_list(MinFieldWidth - erlang:length(Decimal)) ++ "s",
- Spaces = io_lib:format(SpaceFormat,[""]),
- ?debugFmt("Spaces: |~s|", [Spaces]),
- ?debugFmt("Decimal: ~s", [Decimal]),
- [lists:flatten(Decimal ++ Spaces)];
- stringformat_io(Input, _Conversion, _ConversionFlag, MinFieldWidth,
- _Precision, PrecisionLength, "d") when MinFieldWidth > 0 ->
- %Format = "~" ++ re:replace(Conversion, "d", "B", [{return, list}] ),
- DecimalFormat = "~" ++ integer_to_list(PrecisionLength) ++ "..0B",
- Decimal = lists:flatten( io_lib:format(DecimalFormat, [cast_to_integer(Input)]) ),
- SpaceFormat = "~" ++ integer_to_list(MinFieldWidth - erlang:length(Decimal)) ++ "s",
- Spaces = io_lib:format(SpaceFormat,[""]),
- ?debugFmt("Spaces: |~s|", [Spaces]),
- ?debugFmt("Decimal: ~s", [Decimal]),
- [lists:flatten(Spaces ++ Decimal)];
- stringformat_io(Input, _Conversion, _ConversionFlag, _MinFieldWidth,
- _Precision, PrecisionLength, "d") ->
- %Conversion = [ConversionFlag, MinFieldWidth, Precision, PrecisionLength, ConversionType],
- %Format = "~" ++ PrecisionLength ++ "..0" ++ re:replace(Conversion, "d", "B", [{return, list}] ),
- %?debugFmt("precision d, Conversion: ~p~n", [Conversion]),
- Format = lists:flatten("~" ++ io_lib:format("~B..0B",[PrecisionLength])),
- ?debugFmt("Format: ~p~n",[Format]),
- io_lib:format(Format, [cast_to_integer(Input)]);
- stringformat_io(Input, Conversion, _ConversionFlag, _MinFieldWidth,
- _Precision, _PrecisionLength, "i")->
- Format = "~" ++ re:replace(Conversion, "i", "B", [{return, list}] ),
- io_lib:format(Format, [cast_to_integer(Input)]);
- stringformat_io(Input, Conversion, _ConversionFlag, _MinFieldWidth,
- _Precision, _PrecisionLength, "X")->
- Format = "~" ++ re:replace(Conversion, "X", ".16B", [{return, list}] ),
- io_lib:format(Format, [cast_to_integer(Input)]);
- stringformat_io(Input, Conversion, _ConversionFlag, _MinFieldWidth,
- _Precision, _PrecisionLength, "x")->
- Format = "~" ++ re:replace(Conversion, "x", ".16b", [{return, list}] ),
- io_lib:format(Format, [cast_to_integer(Input)]);
- stringformat_io(Input, Conversion, _ConversionFlag, _MinFieldWidth,
- _Precision, _PrecisionLength, "o")->
- Format = "~" ++ re:replace(Conversion, "o", ".8b", [{return, list}] ),
- io_lib:format(Format, [cast_to_integer(Input)]);
- stringformat_io(Input, _Conversion, _ConversionFlag, _MinFieldWidth,
- Precision, PrecisionLength, "e") when is_integer(PrecisionLength), PrecisionLength >= 2->
- ?debugFmt("PrecisionLength ~p~n", [PrecisionLength]),
- Conversion1 = lists:concat(["","",Precision,PrecisionLength + 1,"e"]),
- Format = "~" ++ Conversion1,
- io_lib:format(Format, [cast_to_float(Input)]);
- stringformat_io(Input, Conversion, ConversionFlag, MinFieldWidth,
- "", [], "e")->
- Format = "~" ++ re:replace(Conversion, "e", ".6e", [{return, list}] ),
- Raw = lists:flatten(stringformat_io(Input, Format, ConversionFlag, MinFieldWidth,
- ".", 6, "e")
- ),
- %io:format("Raw: ~p~n", [Raw]),
- Elocate = string:rstr(Raw,"e+"),
- %io:format("Elocate: ~p~n", [Elocate]),
- String = [string:substr(Raw,1,Elocate-1) ++ "e+"
- ++ io_lib:format("~2..0B",[list_to_integer(string:substr(Raw,Elocate+2))])], %works till +99, then outputs "**"
- %io:format("String: ~p~n", [String]),
- String;
- stringformat_io(Input, Conversion, ConversionFlag, MinFieldWidth,
- Precision, PrecisionLength, "E")->
- Format = re:replace(Conversion, "E", "e", [{return, list}] ),
- [Str] = stringformat_io(Input, Format, ConversionFlag, MinFieldWidth,
- Precision, PrecisionLength, "e"),
- [string:to_upper(Str)].
- %% @doc Strips all [X]HTML tags.
- striptags(Input) when is_binary(Input) ->
- striptags(unicode:characters_to_list(Input));
- striptags(Input) ->
- Regex = "(<[^>]+>)",
- Result = re:replace(Input,Regex,"", [global,{return,list}]),
- Result.
- cast_to_float([]) ->
- [];
- cast_to_float(Input) when is_float(Input) ->
- Input;
- cast_to_float(Input) when is_integer(Input) ->
- Input + 0.0;
- cast_to_float(Input) when is_binary(Input) ->
- %% be compatible with releases prior to R16B
- case erlang:function_exported(erlang, binary_to_float, 1) of
- true ->
- try erlang:binary_to_float(Input)
- catch
- error:_Reason ->
- erlang:binary_to_integer(Input) + 0.0
- end;
- false ->
- cast_to_float(binary_to_list(Input))
- end;
- cast_to_float(Input) when is_list(Input) ->
- try list_to_float(Input)
- catch
- error:_Reason ->
- list_to_integer(Input) + 0.0
- end.
- cast_to_integer([]) ->
- [];
- cast_to_integer(Input) when is_integer(Input) ->
- Input;
- cast_to_integer(Input) when is_float(Input) ->
- erlang:round(Input);
- cast_to_integer(Input) when is_binary(Input) ->
- cast_to_integer(unicode:characters_to_list(Input));
- cast_to_integer(Input) when is_list(Input)->
- case lists:member($., Input) of
- true ->
- erlang:round(erlang:list_to_float(Input));
- false ->
- erlang:list_to_integer(Input)
- end.
- cast_to_list(Input) when is_list(Input) -> Input;
- cast_to_list(Input) when is_binary(Input) -> binary_to_list(Input);
- cast_to_list(Input) when is_atom(Input) -> atom_to_list(Input);
- cast_to_list(Input) -> hd(io_lib:format("~p", [Input])).
- %% @doc Converts to lowercase, removes non-word characters (alphanumerics and underscores) and converts spaces to hyphens.
- slugify(Input) when is_binary(Input) ->
- slugify(unicode:characters_to_list(Input));
- slugify(Input) when is_list(Input) ->
- slugify(Input, []).
- %% @doc Formats a time according to the given format.
- time(Input) ->
- date(Input, "f a").
- time(Input, FormatStr) ->
- date(Input, FormatStr).
- timesince(Date) ->
- timesince(Date, calendar:local_time()).
- %%algorithm taken from django code
- timesince(Date,Comparison) ->
- Since = calendar:datetime_to_gregorian_seconds(Comparison) - calendar:datetime_to_gregorian_seconds(Date),
- timesince0(Since, [], 0).
- timesince0(_, Acc, 2) ->
- string:join(lists:reverse(Acc), ", ");
- timesince0(Seconds, Acc, Terms) when Seconds >= ?SECONDS_PER_YEAR ->
- Years = Seconds div ?SECONDS_PER_YEAR,
- timesince0(Seconds rem ?SECONDS_PER_YEAR, [io_lib:format("~B ~s~s", [Years, "year", pluralize(Years)])|Acc], Terms+1);
- timesince0(Seconds, Acc, Terms) when Seconds >= ?SECONDS_PER_MONTH ->
- Months = Seconds div ?SECONDS_PER_MONTH,
- timesince0(Seconds rem ?SECONDS_PER_MONTH, [io_lib:format("~B ~s~s", [Months, "month", pluralize(Months)])|Acc], Terms+1);
- timesince0(Seconds, Acc, Terms) when Seconds >= ?SECONDS_PER_WEEK ->
- Weeks = Seconds div ?SECONDS_PER_WEEK,
- timesince0(Seconds rem ?SECONDS_PER_WEEK, [io_lib:format("~B ~s~s", [Weeks, "week", pluralize(Weeks)])|Acc], Terms+1);
- timesince0(Seconds, Acc, Terms) when Seconds >= ?SECONDS_PER_DAY ->
- Days = Seconds div ?SECONDS_PER_DAY,
- timesince0(Seconds rem ?SECONDS_PER_DAY, [io_lib:format("~B ~s~s", [Days, "day", pluralize(Days)])|Acc], Terms+1);
- timesince0(Seconds, Acc, Terms) when Seconds >= ?SECONDS_PER_HOUR ->
- Hours = Seconds div ?SECONDS_PER_HOUR,
- timesince0(Seconds rem ?SECONDS_PER_HOUR, [io_lib:format("~B ~s~s", [Hours, "hour", pluralize(Hours)])|Acc], Terms+1);
- timesince0(Seconds, Acc, Terms) when Seconds >= ?SECONDS_PER_MINUTE ->
- Minutes = Seconds div ?SECONDS_PER_MINUTE,
- timesince0(Seconds rem ?SECONDS_PER_MINUTE,[io_lib:format("~B ~s~s", [Minutes, "minute", pluralize(Minutes)])|Acc], Terms+1);
- timesince0(Seconds, Acc, Terms) when Seconds >= 1 ->
- timesince0(0, [io_lib:format("~B ~s~s", [Seconds, "second", pluralize(Seconds)])|Acc], Terms+1);
- timesince0(Seconds, [], 0) when Seconds =< 0 ->
- timesince0(0, ["0 minutes"], 1);
- timesince0(0, Acc, Terms) ->
- timesince0(0, Acc, Terms+1).
- timeuntil(Date) ->
- timesince(calendar:local_time(),Date).
- timeuntil(Date,Comparison) ->
- timesince(Comparison,Date).
- %% @doc Converts a string into titlecase.
- title(Input) when is_binary(Input) ->
- title(unicode:characters_to_list(Input));
- title(Input) when is_list(Input) ->
- title(lower(Input), []).
- %% @doc Truncates a string after a certain number of characters.
- truncatechars(Input, Max) ->
- truncatechars_io(cast_to_list(Input), Max, []).
- %% @doc Truncates a string after a certain number of words.
- truncatewords(_Input, Max) when Max < 0 ->
- "";
- truncatewords(Input, Max) when is_binary(Input) ->
- unicode:characters_to_binary(truncatewords(unicode:characters_to_list(Input), Max));
- truncatewords(Input, Max) ->
- truncatewords_io(cast_to_list(Input), Max, []).
- %% @doc Similar to truncatewords, except that it is aware of HTML tags.
- truncatewords_html(_Input, Max) when Max < 0 ->
- "";
- truncatewords_html(Input, Max) when is_binary(Input) ->
- unicode:characters_to_binary(truncatewords_html(unicode:characters_to_list(Input), Max));
- truncatewords_html(Input, Max) ->
- truncatewords_html_io(cast_to_list(Input), Max, [], [], text).
- %% @doc Recursively takes a self-nested list and returns an HTML unordered list -- WITHOUT opening and closing `<ul>' tags.
- unordered_list(List) ->
- String = lists:flatten(unordered_list(List, [])),
- string:substr(String, 5, erlang:length(String) - 9).
-
- unordered_list([], Acc) ->
- ["<ul>", lists:reverse(Acc), "</ul>"];
- unordered_list([First|_] = List, []) when is_integer(First) ->
- "<li>"++List;
- unordered_list([First|Rest], Acc) when is_list(First), Rest == [] ->
- unordered_list(Rest, ["</li>"] ++ [unordered_list(First, []) | Acc ]) ;
- unordered_list([First|Rest], Acc) when is_list(First), is_integer(hd(hd(Rest))) ->
- unordered_list(Rest, [unordered_list(First, []) ++ "</li>" |Acc]);
- unordered_list([First|Rest], Acc) when is_list(First) ->
- unordered_list(Rest, [unordered_list(First, [])|Acc]).
- %% @doc Converts a string into all uppercase.
- upper(Input) when is_binary(Input) ->
- unicode:characters_to_binary(upper(unicode:characters_to_list(Input)));
- upper(Input) ->
- string:to_upper(Input).
- %% @doc Escapes a value for use in a URL.
- urlencode(Input) ->
- urlencode(Input, <<"/">>).
- urlencode(Input, Safe) when is_binary(Input) ->
- urlencode_io(Input, Safe, 0);
- urlencode(Input, Safe) when is_list(Input) ->
- urlencode_io(Input, Safe, []).
- %% @doc Returns the number of words.
- wordcount(Input) when is_binary(Input) ->
- wordcount(unicode:characters_to_list(Input));
- wordcount(Input) when is_list(Input) ->
- wordcount(Input, 0).
- %% @doc Wraps words at specified line length, uses `<BR/>' html tag to delimit lines
- wordwrap(Input, Number) when is_binary(Input) ->
- wordwrap(unicode:characters_to_list(Input), Number);
- wordwrap(Input, Number) when is_list(Input) ->
- wordwrap(Input, [], [], 0, Number).
- %% @doc Given a string mapping values for true, false and (optionally) undefined, returns one of those strings according to the value.
- yesno(Bool, Choices) when is_binary(Choices) ->
- yesno_io(Bool, Choices);
- yesno(Bool, Choices) when is_list(Choices) ->
- yesno_io(Bool, unicode:characters_to_binary(Choices)).
- % internal
- addslashes([], Acc) ->
- lists:reverse(Acc);
- addslashes([H|T], Acc) when H =:= $"; H =:= $' ->
- addslashes(T, [H, $\\|Acc]);
- addslashes([H|T], Acc) ->
- addslashes(T, [H|Acc]).
- cut([], _, Acc) ->
- lists:reverse(Acc);
- cut([H|T], H, Acc) ->
- cut(T, H, Acc);
- cut([H|T], Char, Acc) ->
- cut(T, Char, [H|Acc]).
- escape(Binary, Index) when is_binary(Binary) ->
- case Binary of
- <<Pre:Index/binary, $<, Post/binary>> ->
- process_binary_match(Pre, <<"<">>, size(Post), escape(Post, 0));
- <<Pre:Index/binary, $>, Post/binary>> ->
- process_binary_match(Pre, <<">">>, size(Post), escape(Post, 0));
- <<Pre:Index/binary, $&, Post/binary>> ->
- process_binary_match(Pre, <<"&">>, size(Post), escape(Post, 0));
- <<Pre:Index/binary, 34, Post/binary>> ->
- process_binary_match(Pre, <<""">>, size(Post), escape(Post, 0));
- <<Pre:Index/binary, 39, Post/binary>> ->
- process_binary_match(Pre, <<"'">>, size(Post), escape(Post, 0));
- <<_:Index/binary, _, _/binary>> ->
- escape(Binary, Index + 1);
- Binary ->
- Binary
- end;
- escape([], Acc) ->
- lists:reverse(Acc);
- escape("<" ++ Rest, Acc) ->
- escape(Rest, lists:reverse("<", Acc));
- escape(">" ++ Rest, Acc) ->
- escape(Rest, lists:reverse(">", Acc));
- escape("&" ++ Rest, Acc) ->
- escape(Rest, lists:reverse("&", Acc));
- escape("\"" ++ Rest, Acc) ->
- escape(Rest, lists:reverse(""", Acc));
- escape("'" ++ Rest, Acc) ->
- escape(Rest, lists:reverse("'", Acc));
- escape([S | Rest], Acc) when is_list(S); is_binary(S)->
- escape(Rest, [force_escape(S) | Acc]);
- escape([C | Rest], Acc) ->
- escape(Rest, [C | Acc]).
- escapejs([], Acc) ->
- lists:reverse(Acc);
- escapejs([C | Rest], Acc) when C < 32; C =:= $"; C =:= $'; C =:= $\\; C =:= $<;
- C =:= $>; C =:= $&; C =:= $=; C =:= $-; C =:= $;;
- C =:= 8232; C =:= 8233 -> % just following django here...
- escapejs(Rest, lists:reverse(lists:flatten(io_lib:format("\\u~4.16.0B", [C])), Acc));
- escapejs([C | Rest], Acc) ->
- escapejs(Rest, [C | Acc]).
- filesizeformat(Bytes, UnitStr) ->
- lists:flatten(io_lib:format("~.1f ~s", [Bytes, UnitStr])).
- fix_ampersands(Input, Index) when is_binary(Input) ->
- case Input of
- <<Pre:Index/binary, $&, Post/binary>> ->
- process_binary_match(Pre, <<"&">>, size(Post), Post);
- <<_:Index/binary, _/binary>> ->
- fix_ampersands(Input, Index + 1);
- _ ->
- Input
- end;
- fix_ampersands([], Acc) ->
- lists:reverse(Acc);
- fix_ampersands("&" ++ Rest, Acc) ->
- fix_ampersands(Rest, lists:reverse("&", Acc));
- fix_ampersands([C | Rest], Acc) ->
- fix_ampersands(Rest, [C | Acc]).
- iriencode([], Acc) ->
- lists:reverse(Acc);
- iriencode([C | Rest], Acc) when ?NO_IRI_ENCODE(C) ->
- iriencode(Rest, [C | Acc]);
- iriencode([$\s | Rest], Acc) ->
- iriencode(Rest, [$+ | Acc]);
- iriencode([C | Rest], Acc) ->
- <<Hi:4, Lo:4>> = <<C>>,
- iriencode(Rest, [hexdigit(Lo), hexdigit(Hi), $\% | Acc]).
- join_io([], _Sep) -> [];
- join_io([_] = X, _Sep) -> X;
- join_io([X|T], Sep) -> [X,Sep] ++ join_io(T, Sep).
- linebreaksbr(Input, Index) when is_binary(Input) ->
- Break = <<"<br />">>,
- case Input of
- <<Pre:Index/binary, $\r, $\n, Post/binary>> ->
- process_binary_match(Pre, Break, size(Post), linebreaksbr(Post, 0));
- <<Pre:Index/binary, $\n, Post/binary>> ->
- process_binary_match(Pre, Break, size(Post), linebreaksbr(Post, 0));
- <<_:Index/binary, _/binary>> ->
- linebreaksbr(Input, Index + 1);
- _ ->
- Input
- end;
- linebreaksbr([], Acc) ->
- lists:reverse(Acc);
- linebreaksbr("\r\n" ++ Rest, Acc) ->
- linebreaksbr(Rest, lists:reverse("<br />", Acc));
- linebreaksbr("\n" ++ Rest, Acc) ->
- linebreaksbr(Rest, lists:reverse("<br />", Acc));
- linebreaksbr([C | Rest], Acc) ->
- linebreaksbr(Rest, [C | Acc]).
- lower(Input, Index) ->
- case Input of
- <<Pre:Index/binary, Byte, Post/binary>> when Byte >= $A andalso Byte =< $Z ->
- process_binary_match(Pre, <<(Byte - $A + $a)>>, size(Post), lower(Post, 0));
- <<_:Index/binary, _/binary>> ->
- lower(Input, Index + 1);
- _ ->
- Input
- end.
- phone2numeric([], Acc) ->
- lists:reverse(Acc);
- phone2numeric([H|T], Acc) when H >= $a, H =< $c; H >= $A, H =< $C ->
- phone2numeric(T, [$2|Acc]);
- phone2numeric([H|T], Acc) when H >= $d, H =< $f; H >= $D, H =< $F ->
- phone2numeric(T, [$3|Acc]);
- phone2numeric([H|T], Acc) when H >= $g, H =< $i; H >= $G, H =< $I ->
- phone2numeric(T, [$4|Acc]);
- phone2numeric([H|T], Acc) when H >= $j, H =< $l; H >= $J, H =< $L ->
- phone2numeric(T, [$5|Acc]);
- phone2numeric([H|T], Acc) when H >= $m, H =< $o; H >= $M, H =< $O ->
- phone2numeric(T, [$6|Acc]);
- phone2numeric([H|T], Acc) when H >= $p, H =< $s; H >= $P, H =< $S ->
- phone2numeric(T, [$7|Acc]);
- phone2numeric([H|T], Acc) when H >= $t, H =< $v; H >= $T, H =< $V ->
- phone2numeric(T, [$8|Acc]);
- phone2numeric([H|T], Acc) when H >= $w, H =< $z; H >= $W, H =< $Z ->
- phone2numeric(T, [$9|Acc]);
- phone2numeric([H|T], Acc) ->
- phone2numeric(T, [H|Acc]).
- slugify([], Acc) ->
- lists:reverse(Acc);
- slugify([H|T], Acc) when H >= $A, H =< $Z ->
- slugify(T, [H-$A+$a|Acc]);
- slugify([$\ |T], Acc) ->
- slugify(T, [$-|Acc]);
- slugify([H|T], Acc) when H >= $a, H =< $z; H >= $0, H =< $9; H =:= $_ ->
- slugify(T, [H|Acc]);
- slugify([_|T], Acc) ->
- slugify(T, Acc).
- title([], Acc) ->
- lists:reverse(Acc);
- title([Char | Rest], [] = Acc) when Char >= $a, Char =< $z ->
- title(Rest, [Char + ($A - $a) | Acc]);
- title([Char | Rest], [Sep|[Sep2|_Other]] = Acc)
- when Char >= $a, Char =< $z,
- not (Sep >= $a andalso Sep =< $z),
- not (Sep >= $A andalso Sep =< $Z),
- not (Sep >= $0 andalso Sep =< $9),
- not (Sep =:= $' andalso (Sep2 >= $a andalso Sep2 =< $z)) ->
- title(Rest, [Char + ($A - $a) | Acc]);
- title([Char | Rest], Acc) ->
- title(Rest, [Char | Acc]).
- truncatechars_io([], _CharsLeft, Acc) ->
- lists:reverse(Acc);
- truncatechars_io(_Input, 0, Acc) ->
- lists:reverse("..." ++ drop_chars(Acc, 3));
- truncatechars_io([C|Rest], CharsLeft, Acc) when C >= 2#11111100 ->
- truncatechars_io(Rest, CharsLeft + 4, [C|Acc]);
- truncatechars_io([C|Rest], CharsLeft, Acc) when C >= 2#11111000 ->
- truncatechars_io(Rest, CharsLeft + 3, [C|Acc]);
- truncatechars_io([C|Rest], CharsLeft, Acc) when C >= 2#11110000 ->
- truncatechars_io(Rest, CharsLeft + 2, [C|Acc]);
- truncatechars_io([C|Rest], CharsLeft, Acc) when C >= 2#11100000 ->
- truncatechars_io(Rest, CharsLeft + 1, [C|Acc]);
- truncatechars_io([C|Rest], CharsLeft, Acc) when C >= 2#11000000 ->
- truncatechars_io(Rest, CharsLeft, [C|Acc]);
- truncatechars_io([C|Rest], CharsLeft, Acc) ->
- truncatechars_io(Rest, CharsLeft - 1, [C|Acc]).
- drop_chars([], _) -> [];
- drop_chars(Cs, 0) -> Cs;
- drop_chars([C|Cs], Count) when C >= 2#11111100 ->
- drop_chars(Cs, Count + 4);
- drop_chars([C|Cs], Count) when C >= 2#11111000 ->
- drop_chars(Cs, Count + 3);
- drop_chars([C|Cs], Count) when C >= 2#11110000 ->
- drop_chars(Cs, Count + 2);
- drop_chars([C|Cs], Count) when C >= 2#11100000 ->
- drop_chars(Cs, Count + 1);
- drop_chars([C|Cs], Count) when C >= 2#11000000 ->
- drop_chars(Cs, Count);
- drop_chars([_|Cs], Count) ->
- drop_chars(Cs, Count - 1).
- truncatewords_io([], _WordsLeft, Acc) ->
- lists:reverse(Acc);
- truncatewords_io(_Input, 0, Acc) ->
- lists:reverse("... " ++ Acc);
- truncatewords_io([C1, C2|Rest], WordsLeft, Acc) when C1 =/= $\s andalso C2 =:= $\s ->
- truncatewords_io([C2|Rest], WordsLeft - 1, [C1|Acc]);
- truncatewords_io([C1|Rest], WordsLeft, Acc) ->
- truncatewords_io(Rest, WordsLeft, [C1|Acc]).
- truncatewords_html_io([], _WordsLeft, Acc, [], _) ->
- lists:reverse(Acc);
- truncatewords_html_io(_Input, 0, Acc, [], _) ->
- lists:reverse(Acc);
- truncatewords_html_io(Input, 0, Acc, [Tag|RestOfTags], done) ->
- truncatewords_html_io(Input, 0, ">"++Tag++"/<" ++ Acc, RestOfTags, done);
- truncatewords_html_io(Input, 0, Acc, [Tag|RestOfTags], _) ->
- truncatewords_html_io(Input, 0, "...>"++Tag++"/<" ++ Acc, RestOfTags, done);
- truncatewords_html_io([], WordsLeft, Acc, [Tag|RestOfTags], _) ->
- truncatewords_html_io([], WordsLeft, ">"++Tag++"/<" ++ Acc, RestOfTags, text);
- truncatewords_html_io([C|Rest], WordsLeft, Acc, Tags, text) when C =:= $< ->
- truncatewords_html_io(Rest, WordsLeft, [C|Acc], [""|Tags], tag);
- truncatewords_html_io([C1, C2|Rest], WordsLeft, Acc, Tags, text) when C1 =/= $\ , C2 =:= $\ ; C1 =/= $\ , C2 =:= $< ->
- truncatewords_html_io([C2|Rest], WordsLeft - 1, [C1|Acc], Tags, text);
- truncatewords_html_io([C|Rest], WordsLeft, Acc, Tags, text) ->
- truncatewords_html_io(Rest, WordsLeft, [C|Acc], Tags, text);
- truncatewords_html_io([C|Rest], WordsLeft, Acc, [""|Tags], tag) when C =:= $/ ->
- truncatewords_html_io(Rest, WordsLeft, [C|Acc], Tags, close_tag);
- truncatewords_html_io([C|Rest], WordsLeft, Acc, [Tag|RestOfTags], tag) when C >= $a, C =< $z; C >= $A, C =< $Z ->
- truncatewords_html_io(Rest, WordsLeft, [C|Acc], [[C|Tag]|RestOfTags], tag);
- truncatewords_html_io([C|Rest], WordsLeft, Acc, Tags, tag) when C =:= $> ->
- truncatewords_html_io(Rest, WordsLeft, [C|Acc], Tags, text);
- truncatewords_html_io([C|Rest], WordsLeft, Acc, Tags, tag) ->
- truncatewords_html_io(Rest, WordsLeft, [C|Acc], Tags, attrs);
- truncatewords_html_io([C|Rest], WordsLeft, Acc, Tags, attrs) when C =:= $> ->
- truncatewords_html_io(Rest, WordsLeft, [C|Acc], Tags, text);
- truncatewords_html_io([C|Rest], WordsLeft, Acc, [_Tag|RestOfTags], close_tag) when C =:= $> ->
- truncatewords_html_io(Rest, WordsLeft, [C|Acc], RestOfTags, text).
- wordcount([], Count) ->
- Count;
- wordcount([C1], Count) when C1 =/= $\ ->
- Count+1;
- wordcount([C1, C2|Rest], Count) when C1 =/= $\ andalso C2 =:= $\ ->
- wordcount([C2|Rest], Count + 1);
- wordcount([_|Rest], Count) ->
- wordcount(Rest, Count).
- % No more input, we're done
- wordwrap([], Acc, WordAcc, _LineLength, _WrapAt) ->
- lists:reverse(WordAcc ++ Acc);
- % Premature newline
- wordwrap([$\n | Rest], Acc, WordAcc, _LineLength, WrapAt) ->
- wordwrap(Rest, [$\n | WordAcc ++ Acc], [], 0, WrapAt);
- % Hit the wrap length at a space character. Add a newline
- wordwrap([$\ | Rest], Acc, WordAcc, WrapAt, WrapAt) ->
- wordwrap(Rest, [$\n | WordAcc ++ Acc], [], 0, WrapAt);
- % Hit a space character before the wrap length. Keep going
- wordwrap([$\ | Rest], Acc, WordAcc, LineLength, WrapAt) ->
- wordwrap(Rest, [$\ | WordAcc ++ Acc], [], LineLength + 1 + erlang:length(WordAcc), WrapAt);
- % Overflowed the current line while building a word
- wordwrap([C | Rest], Acc, WordAcc, 0, WrapAt) when erlang:length(WordAcc) > WrapAt ->
- wordwrap(Rest, Acc, [C | WordAcc], 0, WrapAt);
- wordwrap([C | Rest], Acc, WordAcc, LineLength, WrapAt) when erlang:length(WordAcc) + LineLength > WrapAt ->
- wordwrap(Rest, [$\n | Acc], [C | WordAcc], 0, WrapAt);
- % Just building a word...
- wordwrap([C | Rest], Acc, WordAcc, LineLength, WrapAt) ->
- wordwrap(Rest, Acc, [C | WordAcc], LineLength, WrapAt).
- urlencode_io(Input, Safe, Index) when is_binary(Input) ->
- case Input of
- <<_:Index/binary, Byte, _/binary>> when ?NO_ENCODE(Byte) ->
- urlencode_io(Input, Safe, Index + 1);
- <<Pre:Index/binary, C:1/binary, Post/binary>> ->
- process_binary_match(
- Pre, maybe_urlencode_char(C, Safe),
- size(Post), urlencode_io(Post, Safe, 0));
- Input ->
- Input
- end;
- urlencode_io([], _Safe, Acc) ->
- lists:reverse(Acc);
- urlencode_io([C | Rest], Safe, Acc) when ?NO_ENCODE(C) ->
- urlencode_io(Rest, Safe, [C | Acc]);
- urlencode_io([C | Rest], Safe, Acc) ->
- urlencode_io(Rest, Safe, [maybe_urlencode_char(<<C>>, Safe) | Acc]).
- maybe_urlencode_char(C, Safe) ->
- case binary:match(Safe, C) of
- nomatch ->
- <<Hi:4, Lo:4>> = C,
- HiDigit = hexdigit(Hi),
- LoDigit = hexdigit(Lo),
- <<$%, HiDigit, LoDigit>>;
- _ -> C
- end.
- %% @doc Converts URLs in text into clickable links.
- %%TODO: Autoescape not yet implemented
- urlize(Input) when is_binary(Input) ->
- urlize(unicode:characters_to_list(Input),0);
- urlize(Input) ->
- urlize(Input,0).
- urlize(Input, Trunc) when is_binary(Input) ->
- urlize(unicode:characters_to_list(Input),Trunc);
- urlize(Input, Trunc) ->
- {ok,RE} = re:compile("(([[:alpha:]]+://|www\.)[^<>[:space:]]+[[:alnum:]/])"),
- RegexResult = re:run(Input,RE,[global]),
- case RegexResult of
- {match, Matches} ->
- Indexes = lists:map(fun(Match) -> lists:nth(2,Match) end, Matches),
- Domains = lists:map(fun({Start, Length}) -> lists:sublist(Input, Start+1, Length) end, Indexes),
- URIDomains = lists:map(fun(Domain) -> addDefaultURI(Domain) end, Domains),
- case Trunc == 0 of
- true ->
- DomainsTrunc = Domains;
- false ->
- DomainsTrunc = lists:map(fun(Domain) -> string:concat( string:substr(Domain,1,Trunc-3), "...") end, Domains)
- end,
- ReplaceList = lists:zip(URIDomains,DomainsTrunc),
- ReplaceStrings = lists:map(fun({URIDomain,Domain}) -> lists:flatten(io_lib:format("<a href=\"~s\" rel=\"nofollow\">~s</a>",[URIDomain,Domain])) end, ReplaceList),
- Template = re:replace(Input,"(([[:alpha:]]+://|www\.)[^<>[:space:]]+[[:alnum:]/])", "~s", [global,{return,list}]),
- Result = lists:flatten(io_lib:format(Template,ReplaceStrings)),
- Result;
- nomatch ->
- Input
- end.
- %% @doc Converts URLs into clickable links just like urlize, but truncates URLs longer than the given character limit.
- urlizetrunc(Input, Trunc) ->
- urlize(Input, Trunc).
- addDefaultURI(Domain) ->
- case string:str(Domain,"://") of
- 0 ->
- Domain1 = string:concat("http://",Domain);
- _ ->
- Domain1 = Domain
- end,
- Domain1.
- hexdigit(C) when C < 10 -> $0 + C;
- hexdigit(C) when C < 16 -> $A + (C - 10).
- process_binary_match(Pre, Insertion, SizePost, Post) ->
- case {size(Pre), SizePost} of
- {0, 0} -> Insertion;
- {0, _} -> [Insertion, Post];
- {_, 0} -> [Pre, Insertion];
- _ -> [Pre, Insertion, Post]
- end.
- yesno_io(Val, Choices) ->
- {True, False, Undefined} =
- case binary:split(Choices, <<",">>, [global]) of
- [T, F, U] -> {T, F, U};
- [T, F] -> {T, F, F};
- _ -> throw({yesno, choices})
- end,
- if Val =:= false -> False;
- Val =:= undefined -> Undefined;
- is_list(Val); is_binary(Val) ->
- case iolist_size(Val) of
- 0 -> False;
- _ -> True
- end;
- true -> True
- end.
- %% unjoin == split in other languages; inverse of join
- %%FROM: http://www.erlang.org/pipermail/erlang-questions/2008-October/038896.html
- unjoin(String, []) ->
- unjoin0(String);
- unjoin(String, [Sep]) when is_integer(Sep) ->
- unjoin1(String, Sep);
- unjoin(String, [C1,C2|L]) when is_integer(C1), is_integer(C2) ->
- unjoin2(String, C1, C2, L).
- %% Split a string at "", which is deemed to occur _between_
- %% adjacent characters, but queerly, not at the beginning
- %% or the end.
- unjoin0([C|Cs]) ->
- [[C] | unjoin0(Cs)];
- unjoin0([]) ->
- [].
- %% Split a string at a single character separator.
- unjoin1(String, Sep) ->
- unjoin1_loop(String, Sep, "").
- unjoin1_loop([Sep|String], Sep, Rev) ->
- [lists:reverse(Rev) | unjoin1(String, Sep)];
- unjoin1_loop([Chr|String], Sep, Rev) ->
- unjoin1_loop(String, Sep, [Chr|Rev]);
- unjoin1_loop([], _, Rev) ->
- [lists:reverse(Rev)].
- %% Split a string at a multi-character separator
- %% [C1,C2|L]. These components are split out for
- %% a fast match.
- unjoin2(String, C1, C2, L) ->
- unjoin2_loop(String, C1, C2, L, "").
- unjoin2_loop([C1|S = [C2|String]], C1, C2, L, Rev) ->
- case unjoin_prefix(L, String)
- of no -> unjoin2_loop(S, C1, C2, L, [C1|Rev])
- ; Rest -> [lists:reverse(Rev) | unjoin2(Rest, C1, C2, L)]
- end;
- unjoin2_loop([Chr|String], C1, C2, L, Rev) ->
- unjoin2_loop(String, C1, C2, L, [Chr|Rev]);
- unjoin2_loop([], _, _, _, Rev) ->
- [lists:reverse(Rev)].
- unjoin_prefix([C|L], [C|S]) -> unjoin_prefix(L, S);
- unjoin_prefix([], S) -> S;
- unjoin_prefix(_, _) -> no.
|