Erlang实战练习(六)
本文主要讲为文本建立索引,通过使用进程字典的方式为文本创建索引,尽管专家提倡尽量避免使用进程字典,但是在初学阶段很容易地就使用了进程字典,当然,除了进程字典方式外,还有其它方式,后面章节我将会使用另外一种方式来保存单词、行数、出现次数,也即Erlang提供的模块:ETS(Erlang Term Storage),后面我们会发现,使用ETS更加方便。
练习:为文本建立索引。
要求:给定一个由英文单词构成的文件,为文件中所有单词建立索引,记录每个单词出现的行号和每行出现的次数,并将索引存入一个文件。
思路:读取文本文件,然后将文本文件分割成单词,然后存储每个单词出现的行数和次数的映射。
代码如下,如有不明白,请联系:
-module(text_index).
-export([indexer/2]).
-import(re, [run/2,replace/4]).
-import(string,[substr/3]).
indexer(FileIn,FileOut) ->
{First,Second} = file:open(FileIn,read),
if
First =:= ok ->
erase(),
L = readAll(FileOut,Second,0),
io:format("~nsuccess:~p~n",[L]);
First =/= ok ->
io:format("Open file error: file doesn't exist!")
end.
readAll(FileOut, S,LineNo) ->
UpdateLineNo = LineNo +1,
OneLine = io:get_line(S,''),
if
OneLine =:= eof ->
io:format("Read file EOF!"),
file:close(S);
OneLine =/= eof ->
[index(FileOut,OneLine,UpdateLineNo) | readAll(FileOut,S,UpdateLineNo)]
end.
index(File,Term,LineNo) ->
Reg ="[a-zA-Z-']+",
case re:run(Term,Reg,[]) of
nomatch ->
Dict = get(),
%%io:format("第(~p)行后索引列表:~p~n",[LineNo,Dict]),
io:format("/********第~p行显示开始********/",[LineNo]),
showInfo(LineNo,Dict),
unconsult(File,Dict);
{match,[{Start,Length}]} ->
Word = string:substr(Term,Start+1,Length),
L = get(Word),
if
L =:= undefined ->
put(Word,[{LineNo,1}]),
%io:format("1---Word:~p Value:~p ~n",[Word,get(Word)]),
NewTerm = re:replace(Term,Word,"?",[{return,list}]),
index(File,NewTerm,LineNo);
L =/= undefined ->
{LN,Num}= lists:nth(1,L),
if
LN =:= LineNo ->
DL = lists:delete({LN,Num},L),
NewL = [{LineNo,Num+1} | DL],
put(Word,NewL),
NewTerm = re:replace(Term,Word,"?",[{return,list}]),
%io:format("2---New Term:~s~n",[NewTerm]),
index(File,NewTerm,LineNo);
LN =/= LineNo ->
NewL = [{LineNo,1}| L],
put(Word,NewL),
%io:format("3---L:~p NewL:~p Word:~p Value:~p~n",[L,NewL,Word,get(Word)]),
NewTerm = re:replace(Term,Word,"?",[{return,list}]),
index(File,NewTerm,LineNo)
end
end
end.
unconsult(File,L) ->
{ok,S} = file:open(File,write),
lists:foreach(fun(X) -> io:format(S,"~p.~n",[X]) end, L),
file:close(S).
showInfo(LineNo,[]) ->
io:format("~n/*****第~p行显示结束********/~n",[LineNo]);
showInfo(LineNo,Dict) ->
First = lists:nth(1,Dict),
{Word, L} = First,
io:format("~n单词:~p>>>~n",[Word]),
showIndex(L),
showInfo(LineNo,lists:delete(First,Dict)).
showIndex([]) ->
word_end;
showIndex(L) ->
First = lists:nth(1,L),
{LineNo,Num} = First,
io:format(" 出现行号:~p 出现次数:~p ",[LineNo,Num]),
showIndex(lists:delete(First,L)).
运行结果示意图:(控制输出每行索引结果)
执行完毕后,索引结果文件内容:(文档索引存放形式为:{单词,[{行号,出现次数},{...}]} )
分析:本文通过讲述了为文本建立索引,本文使用的方法有点粗糙,拆分单词使用的是正则表达式匹配与替换,过于复杂,应该直接调用string:token函数拆分单词,简单而又明了,同时,使用了尽量避免使用的进程字典方式存储单词索引,不够灵活。本文只做大家的参考,总体看来,代码非常的让人读之不爽,但是我为什么又将它拿出来分析呢,一是因为这是初学Erlang时的劣作,对于很多知识和模块不是很熟悉,因此难免无从下手;二是因为通过此文本索引的分析,让自己进一步对于程序设计有更加深刻的了解,算是另一种思考吧。尽请关注下文的改进方法吧!
注:如无特殊说明,本博客内容纯属原创,转载请注明:http://www.cnblogs.com/itfreer/ | IT闲人,谢谢!