From a6c89679cd6006b3e9839b426159fd4302321528 Mon Sep 17 00:00:00 2001 From: Patrik Nyblom Date: Thu, 22 Apr 2010 18:45:36 +0200 Subject: Add binary:part to erl_bif_binary.c Change name of the 'scope' option for binary:match/matches. Add split and replace to binary.erl. Cleanup comments etc in binary.erl and atom.names Add testcases for part, split, replace and scopes. --- lib/stdlib/src/binary.erl | 203 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 150 insertions(+), 53 deletions(-) (limited to 'lib/stdlib/src/binary.erl') diff --git a/lib/stdlib/src/binary.erl b/lib/stdlib/src/binary.erl index d649f974bb..3eaf011db4 100644 --- a/lib/stdlib/src/binary.erl +++ b/lib/stdlib/src/binary.erl @@ -20,61 +20,158 @@ %% %% The following functions implemented as BIF's %% binary:compile_pattern/1 -%% binary:find/3 -%% XXX:PaN more to come... - --export([first/1,first/2,last/1,last/2,nth/2,extract/3]). +%% binary:match/{2,3} +%% binary:matches/{2,3} +%% - Not yet: +%% binary:longest_common_prefix/1 +%% binary:longest_common_suffix/1 +%% binary:first/1 +%% binary:last/1 +%% binary:at/2 +%% binary:part/{2,3} +%% binary:bin_to_list/{1,2,3} +%% binary:list_to_bin/1 +%% binary:copy/{1,2} +%% binary:referenced_byte_size/1 +%% binary:decode_unsigned/{1,2} +%% +%% Implemented in this module: +-export([split/2,split/3,replace/3,replace/4]). -first(<>) -> - F; -first(_) -> - erlang:error(badarg). -first(N,Bin) when is_integer(N), N >= 0 -> - case Bin of - <> -> - F; - _ -> +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% split +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +split(H,N) -> + split(H,N,[]). +split(Haystack,Needles,Options) -> + try + {Part,Global,Trim} = get_opts_split(Options,{no,false,false}), + Moptlist = case Part of + no -> + []; + {A,B} -> + [{scope,{A,B}}] + end, + MList = if + Global -> + binary:matches(Haystack,Needles,Moptlist); + true -> + case binary:match(Haystack,Needles,Moptlist) of + nomatch -> []; + Match -> [Match] + end + end, + do_split(Haystack,MList,0,Trim) + catch + _:_ -> erlang:error(badarg) - end; -first(_,_) -> - erlang:error(badarg). -last(<<>>) -> - erlang:error(badarg); -last(Bin) when is_binary(Bin) -> - Sz = byte_size(Bin) - 1, - <<_:Sz/binary,L:1/binary>> = Bin, - L; -last(_) -> - erlang:error(badarg). -last(N,Bin) when is_integer(N), N >= 0, is_binary(Bin) -> - Sz = byte_size(Bin) - N, - case Bin of - <<_:Sz/binary,L:N/binary>> -> - L; - _ -> - erlang:error(badarg) - end; -last(_,_) -> - erlang:error(badarg). + end. -nth(N, Bin) when is_integer(N), N > 0 -> - M = N - 1, - case Bin of - <<_:M/binary,V:1/binary,_/binary>> -> - V; - _ -> - erlang:error(badarg) - end; -nth(_,_) -> - erlang:error(badarg). +do_split(H,[],N,true) when N >= byte_size(H) -> + []; +do_split(H,[],N,_) -> + [binary:part(H,{N,byte_size(H)-N})]; +do_split(H,[{A,B}|T],N,Trim) -> + case binary:part(H,{N,A-N}) of + <<>> -> + Rest = do_split(H,T,A+B,Trim), + case {Trim, Rest} of + {true,[]} -> + []; + _ -> + [<<>> | Rest] + end; + Oth -> + [Oth | do_split(H,T,A+B,Trim)] + end. -extract(N,Size,Bin) when is_integer(N), is_integer(Size), is_binary(Bin) -> - M = N - 1, - case Bin of - <<_:M/binary,V:Size/binary,_/binary>> -> - V; - _ -> + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% replace +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +replace(H,N,R) -> + replace(H,N,R,[]). +replace(Haystack,Needles,Replacement,Options) -> + try + true = is_binary(Replacement), % Make badarg instead of function clause + {Part,Global,Insert} = get_opts_replace(Options,{no,false,[]}), + Moptlist = case Part of + no -> + []; + {A,B} -> + [{scope,{A,B}}] + end, + MList = if + Global -> + binary:matches(Haystack,Needles,Moptlist); + true -> + case binary:match(Haystack,Needles,Moptlist) of + nomatch -> []; + Match -> [Match] + end + end, + ReplList = case Insert of + [] -> + Replacement; + Y when is_integer(Y) -> + splitat(Replacement,0,[Y]); + Li when is_list(Li) -> + splitat(Replacement,0,lists:sort(Li)) + end, + erlang:iolist_to_binary(do_replace(Haystack,MList,ReplList,0)) + catch + _:_ -> erlang:error(badarg) - end; -extract(_,_,_) -> - erlang:error(badarg). + end. + + +do_replace(H,[],_,N) -> + [binary:part(H,{N,byte_size(H)-N})]; +do_replace(H,[{A,B}|T],Replacement,N) -> + [binary:part(H,{N,A-N}), + if + is_list(Replacement) -> + do_insert(Replacement, binary:part(H,{A,B})); + true -> + Replacement + end + | do_replace(H,T,Replacement,A+B)]. + +do_insert([X],_) -> + [X]; +do_insert([H|T],R) -> + [H,R|do_insert(T,R)]. + +splitat(H,N,[]) -> + [binary:part(H,{N,byte_size(H)-N})]; +splitat(H,N,[I|T]) -> + [binary:part(H,{N,I-N})|splitat(H,I,T)]. + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Simple helper functions +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +get_opts_split([],{Part,Global,Trim}) -> + {Part,Global,Trim}; +get_opts_split([{scope,{A,B}} | T],{_Part,Global,Trim}) -> + get_opts_split(T,{{A,B},Global,Trim}); +get_opts_split([global | T],{Part,_Global,Trim}) -> + get_opts_split(T,{Part,true,Trim}); +get_opts_split([trim | T],{Part,Global,_Trim}) -> + get_opts_split(T,{Part,Global,true}); +get_opts_split(_,_) -> + throw(badopt). + +get_opts_replace([],{Part,Global,Insert}) -> + {Part,Global,Insert}; +get_opts_replace([{scope,{A,B}} | T],{_Part,Global,Insert}) -> + get_opts_replace(T,{{A,B},Global,Insert}); +get_opts_replace([global | T],{Part,_Global,Insert}) -> + get_opts_replace(T,{Part,true,Insert}); +get_opts_replace([{insert_replaced,N} | T],{Part,Global,_Insert}) -> + get_opts_replace(T,{Part,Global,N}); +get_opts_replace(_,_) -> + throw(badopt). + -- cgit v1.2.3