%%% -*- mode: erlang -*- %%% $Id: regexmatch.erlang,v 1.7 2001/01/06 22:35:23 doug Exp $ %%% http://www.bagley.org/~doug/shootout/ -module(regexmatch). -export([main/0, main/1]). %% get the program argument, which is how many test iterations to run main() -> main(['1']). main([Arg]) -> Num = list_to_integer(atom_to_list(Arg)), {ok, Re} = regexp:parse( "(^|[^0-9\\(])" % preceeding non-digit or bol "(" % area code "\\([0-9][0-9][0-9]\\)" % is either 3 digits in parens "|" % or "[0-9][0-9][0-9]" % just 3 digits ")" % end of area code " " % area code is followed by one space "[0-9][0-9][0-9]" % exchange is 3 digits "[ -]" % separator is either space or dash "[0-9][0-9][0-9][0-9]" % last 4 digits "($|[^0-9])" % must be followed by a non-digit ), Plist = readlines(), test(Num, Re, Plist), halt(0). test(1, Regexp, Plist) -> % display output on last iteration Nums = match_phones(Regexp, Plist), print_phones(1, Nums), true; test(N, Regexp, Plist) -> match_phones(Regexp, Plist), test(N-1, Regexp, Plist). print_phones(Count, [H|T]) -> [A,E,N] = H, % A,E,N is a list of the matching sub-expressions, which are: % Areacode (3 digits), Exchange (3 digits), Number (4 digits) io:fwrite("~w: (~s) ~s-~s~n", [Count, A,E,N]), print_phones(Count+1, T); print_phones(_, []) -> true. match_phones(Regexp, List) -> mapfilter( fun(String) -> case regexp:matches(String, Regexp) of {match, []} -> false; {match, Matches} -> parse_phone(String, Matches); _ -> false end end, List). parse_phone(Str, [H|T]) -> {Start, Len} = H, % Numstr is something that looks like a complete phone # Numstr = string:substr(Str, Start, Len), case regexp:matches(Numstr, "[0-9][0-9][0-9][0-9]*") of {match, []} -> false; {match, Matches} -> lists:map(fun({Offset, Length}) -> string:substr(Numstr, Offset, Length) end, Matches); _ -> false end; parse_phone(Str, []) -> []. mapfilter(Fun, [H|T]) -> case Fun(H) of false -> mapfilter(Fun, T); New -> [New | mapfilter(Fun, T)] end; mapfilter(_, []) -> []. readlines() -> Port = open_port({fd, 0, 1}, [eof, {line, 512}]), readlines_from_stream([], Port). readlines_from_stream(Lines, Port) -> receive {Port, eof} -> lists:reverse(Lines); {Port, {_, {_, Line}}} -> readlines_from_stream([Line|Lines], Port) end.