Applying a Function to Each Line of a String
From Erlang Community
(Difference between revisions)
| Revision as of 00:51, 15 October 2006 (edit) Ayrnieu (Talk | contribs) (new recipe) ← Previous diff |
Current revision (00:53, 15 October 2006) (edit) (undo) Ayrnieu (Talk | contribs) m (*facepalm* same typo; also remove ugly captions) |
||
| Line 9: | Line 9: | ||
| provided that you don't mind eliding blank lines: | provided that you don't mind eliding blank lines: | ||
| - | <code | + | <code> |
| 1> string:tokens("hello\r\nthere\r\nmon\r\rfrere\n","\r\n"). | 1> string:tokens("hello\r\nthere\r\nmon\r\rfrere\n","\r\n"). | ||
| ["hello","there","mon","frere"] | ["hello","there","mon","frere"] | ||
| Line 17: | Line 17: | ||
| 'lines', you can use regexp:split/2: | 'lines', you can use regexp:split/2: | ||
| - | <code | + | <code> |
| 2> regexp:split("hello\r\nthere\r\nmon\r\rfrere\n","\r\n"). | 2> regexp:split("hello\r\nthere\r\nmon\r\rfrere\n","\r\n"). | ||
| {ok,["hello","there","mon\r\rfrere\n"]} | {ok,["hello","there","mon\r\rfrere\n"]} | ||
| Line 32: | Line 32: | ||
| respectively. | respectively. | ||
| - | <code | + | <code> |
| foreach_line(F,L) -> | foreach_line(F,L) -> | ||
| lists:reverse(lists:foldl(fun (C,[]) when C == $\r orelse C == $\n -> []; | lists:reverse(lists:foldl(fun (C,[]) when C == $\r orelse C == $\n -> []; | ||
| Line 60: | Line 60: | ||
| </code> | </code> | ||
| - | [[Category: | + | [[Category:CookBook]][[Category:ListRecipes]] |
Current revision
[edit] 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.
[edit] Solution
You can neatly divide the string into lines with string:tokens/2, provided that you don't mind eliding blank lines:
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:
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(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

