Applying a Function to Each Line of a String
From Erlang Community
Problem
You'd like to apply a function to a sequence of logical lines within a string, without regard for the sort of newlines (Unix, Mac, DOS) involved.
Solution
You can neatly divide the string into lines with string:tokens/2, provided that you don't mind eliding blank lines:
string:tokens/2 |
1> string:tokens("hello\r\nthere\r\nmon\r\rfrere\n","\r\n").
["hello","there","mon","frere"]
|
If you must also have the blank lines, or if you've complex ideas about 'lines', you can use regexp:split/2:
regexp:split/ |
2> regexp:split("hello\r\nthere\r\nmon\r\rfrere\n","\r\n").
{ok,["hello","there","mon\r\rfrere\n"]}
3> regexp:split("hello\r\nthere\r\nmon\r\rfrere\n","[\r\n]+").
{ok,["hello","there","mon","frere",[]]}
4> regexp:split("hello\r\nthere\r\nmon\r\rfrere\nfoo","[\r\n]+").
{ok,["hello","there","mon","frere","foo"]}
|
You can also use foreach_line/2 and mapeach_line/2; these elid blank lines, and have the same line semantics as the first string:tokens/2 solution, but you can easily adapt these. These also return the remainder of the string and the {remainder(),mapped_results()}, respectively.
foreach_line/2 and mapeach_line/2 |
foreach_line(F,L) ->
lists:reverse(lists:foldl(fun (C,[]) when C == $\r orelse C == $\n -> [];
(C,S) when C == $\r orelse C == $\n ->
F(lists:reverse(S)), [];
(C,S) ->
[C|S]
end, [], L)).
mapeach_line(F,L) ->
{R,M} = lists:foldl(fun (C,R={[],_}) when C == $\r orelse C == $\n -> R;
(C,{S,M}) when C == $\r orelse C == $\n ->
{[],[F(lists:reverse(S))|M]};
(C,{S,M}) ->
{[C|S],M}
end, {[],[]}, L),
{lists:reverse(R), lists:reverse(M)}.
5> foreach_line(fun(S) -> io:fwrite("l; ~s\n",[S]) end,"hello\r\nthere\rmon\n\rfrere\n\nfoo").
l; hello
l; there
l; mon
l; frere
"foo"
6> mapeach_line(fun lists:reverse/1, "hello\r\nthere\rmon\n\rfrere\n\nfoo").
{"foo",["olleh","ereht","nom","ererf"]}
|

Digg It
Del.icio.us
Reddit
Facebook
Stumble Upon
Technorati

