android 电子书阅读器epub解析、全文关键字搜索功能

时间:2024-04-02 11:11:01

         上半年公司一直很忙  也没时间将此功能进行整理   我相信大多数人还是需要的    先说一下此功能的背景吧   之前阅读器是嵌入的H5自然与我们关系不大   后来领导说要采用原生的阅读器还要支持epub格式解析、更为重要的是需要全文关键字检索   这可把我难住了  因为以前从来没有做过类似的功能   领导只给了一周时间   然后就是各种找三方阅读器、找解析  最后终于结束了  给自己点个赞!!!

     接下来进入正题,首先我找的三方阅读器FBReader  这可以说是目前唯一开源的阅读器  没有之一

项目源码:https://github.com/koreader/koreader  开源项目

当时感觉靠谱所以就开始找类似的项目,果然找到了,于是我就参考源码完成了阅读器的功能,而且这个开源项目是支持epub格式解析的哦  这是我的效果图:android 电子书阅读器epub解析、全文关键字搜索功能android 电子书阅读器epub解析、全文关键字搜索功能android 电子书阅读器epub解析、全文关键字搜索功能android 电子书阅读器epub解析、全文关键字搜索功能

 

    阅读器就这是这个样子,重点说一下关键字全文搜索功能:

-------------------------- 华丽丽的分割线,修改起因 -----------------------------

    FBReader提供了文字搜索功能,但只能通过左右按钮依次进行切换跳转,深感不便,如下图一所示:

              android 电子书阅读器epub解析、全文关键字搜索功能

    本文通过对源码的改进,将搜索功能扩展,搜索结果及其在原文中的位置百分比,以列表的形式展现(并前后添加五个字作为区分),可以通过列表项的点击,轻松跳转到任意一条搜索结果显示页。效果如上图二、图三所示。

-------------------------- 源码分析 -----------------------------

    首先,看下源码搜索的调用逻辑,如下图所示:

android 电子书阅读器epub解析、全文关键字搜索功能

    从上图的调用关系,可以看出,在ZLTextPlainModel里面用private ArrayList<ZLTextMark> myMarks;来保存了ZLTextMark类型的数据,作为搜索结果的存储。

    再来看下ZLTextMark类,里面定义了三个参数,来记录搜索结果在文件中的位置,和长度,以此定位跳转

        public final int ParagraphIndex;

        public final int Offset;

        public final int Length;

    从上图中,亦可看出,搜索的实际操作,是通过ZLSearchUtil类的find方法来实现的。源码中,以忽略大小写模式为例,

在搜索成功后,会返回文字位置偏移,再以此为基础,循环进行下一次搜索,直至结尾:

    if (j >= patternLength) { 
        return i - offset; 
    }

---------------------- 分割线又来了,马上修改代码喽 ----------------------

    通过前面的介绍,大概了解了搜索的过程,和存储。更详细的信息,请查阅源码,不再赘述。

    那么,想达到预期的效果,我做了以下修改:

    修改内容示意图如下:

android 电子书阅读器epub解析、全文关键字搜索功能

    代码部分如下: 

一、为ZLTextMark添加内容参数:

    既然,我们想列表显示,就不能只显示搜索内容,都是一样的噻。因此,添加了public final String AroundContent;参数,来存储搜索结果。在搜索内容的前面和后面,各加了五个字,以做区分。

二、在搜索过程中,为ZLTextMark新参数,拼接内容:

    在ZLSearchUtilfind方法中,搜索成功时,添加了蓝色字体代码,为搜索内容添加前后缀内容:

if (j >= patternLength) { 
    int start = i - AROUND_RANGE; 
    int end = i + patternLength + AROUND_RANGE; 
    // Avoid out of range 
    if(start < 0) start = 0; 
    if(end > text.length - 1) end = text.length - 1; 
    char[] ca = new char[end - start]; 
    for(int m=start; m<end; m++) { 
        ca[m-start] = text[m]; 
    } 
    mAroundContent = String.valueOf(ca); 

    return i - offset; 
}

当然,为外面提供了获取当前内容的接口方法:

    private static String mAroundContent; // current content 
    public final static int AROUND_RANGE = 5; // previous and after additional word number 
    public static String getCurrentAroundContent() { 
        return mAroundContent
    }

三、在搜索存储变量中添加结果内容:

我们已经为ZLTextMark添加了新参数,就在搜索存储时,为其设置,因此,将下面的代码

    myMarks.add(new ZLTextMark(index, offset + pos, pattern.getLength())

添加扩展参数,修改为

   myMarks.add(new ZLTextMark(index, offset + pos, pattern.getLength(), 
    ZLSearchUtil.getCurrentAroundContent()));

经过上述修改,再次获得myMarks内容后,里面存储的ZLTextMark就比原来多出了一项内容,可以供我们在列表中显示了。

---------------------------------- 分割线,再看下列表 ----------------------------------

    看过代码的话,可以了解到ZLTextMarkParagraphIndex参数,是指当前内容所在的段落索引。而我们在打开书籍后,又可以通过myFBReaderApp.Model.getTextModel().getParagraphsNumber();来获取书籍的总段落数量,因此前面显示的百分比,就很容易计算出来了。

    ok,添加前后缀的内容有了,百分比也有了。列表的设置,就不用多说了吧。

    还可以说一句,点击跳转,需要在FBReaderApp中做一个扩展,源码的ZLTextView提供了gotoMark(ZLTextMark mark)方法的,看下源码就晓得了。

------------------------------- 最后的分割线,可以结束了 --------------------------------

    以上,便是修改的全部思路了。希望能对需要的人有所帮助。

    后记:内容只是笔者自己的理解,和实践的一个记录,如有不妥和错误之处,也请及时指出,以便及时更正,以免自误误人。可发至邮箱:[email protected].com