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闲人,谢谢!

posted @ 2012-05-06 20:51  chinagragon  阅读(1913)  评论(0编辑  收藏  举报

Powered by中国龙 博客空间 IT闲人,不干实事