一、建立网页库和偏移文件

为文本搜索引擎建立网页库,首先要把所有的网页(这里是文章)格式化,并保存到指定的格式中。如以下格式:
   |                                  
   |    <doc>                        
   |       <docid>...</docid>      
   |       <url>...</url>           
   |       <title>...</title>         
   |       <content>...</content>     
   |    </doc>                      
   |    <doc>                       
   |      ...                         
   |    </doc>                        
   |    ...

其中<doc>……</doc>保存着一篇文章;<docid>...</docid> 保存文档id;<url>...</url>保存文本路径;<content>...</content> 保存文章内容。

如何生成这样的格式呢?对每一篇文章使用以下方法:

首先从文章中提取标题 title;以及获得文章的路径,然后用字符串拼接,拼接成上述格式。

std::ofstream ofs("pages.lib",std::ios::out);//打开网页库
std::ofstream out("offset.lib",std::ios::out); //打开偏移文件
string txt = "<doc><docid>" + docid + "</docid>" + "<url>" + url + ... + "</doc>";
ofs << txt;     //写到文件流
int offset = ofs.tellg();// offset 获得当前指针的位置 ,tellg()和tellp()是C++文件流操作中获得流指针的函数
int length = txt.size();//length
out<<docid<<" "<<offset<<""<<length<<endl;//将这片文章的起始位置和偏移量写到偏移文件中,便于后面从网页库中读出一篇网页

循环对所有文章执行上面的操作,就得到一个网页库和一个偏移文件。

二、解析网页

根据偏移文件,从网页库中读出一篇网页,接着对网页库中的docid,title,url进行解析。

以下是解析器的代码:

 #ifndef _XMLPARSER_HPP
#define _XMLPARSER_HPP
#include <stdio.h>
#include <utility>
#include <string>
#include <stdlib.h>
using namespace std;
class XMLParser
{
public:
XMLParser(string & page)
:page_(page)
{}
string parser(string tag)
{
string ltag,rtag;
ltag = "<"+tag+">"; //拼接左标签
rtag = "</"+tag+">"; //拼接右标签
string str;
//pair<string,string> pr;
string::size_type bpos;
string::size_type epos;
string::size_type len;
//确定字符串范围
bpos = page_.find(ltag);//查找作标签下标
epos = page_.find(rtag);//查找右标签下标
bpos+=ltag.size();
len = epos - bpos; //计算标签包含内容长度
if(bpos==page_.npos||epos==page_.npos)
{
printf("No such tag: %s \n",tag.c_str());
exit(-);
}
if(bpos==epos)
{
printf("标签内容不存在\n");
exit(-);
} string content = page_.substr(bpos+,len-);//截取标签包含内容
#if 0
if(content[content.size()-]=='\n')
content[content.size()-]=='\0';
if(content[content.size()-]=='\n')
content[content.size()-]=='\0';
if(content[content.size()-]=='\n')
content[content.size()-]=='\0';
#endif
//pr.first = tag;
//pr.second = content;
//return pr; //最好使用std::move,减少复制
return content;
}
private:
string &page_; //使用引用,避免大复制
};
#endif

解析器每次只能传入一个标签,并且返回标签对应的内容,要对所有标签进行解析,那么就要多次调用parser()。当然,对于一篇文章,就对应一个解析器对象,parser()是对外的一个函数,接收标签,并从对象中解析出便签包含的内容。也就是说,创建一个对象可以对这个对象调用多次parser(string tag)对文章进行解析。

三、解析器的使用

首先要有一个加载偏移文件的工具,这里写了一个工具PageOffset.hpp

(代码折叠)代码如下:

#ifndef _PAGEOFFSET_HPP
#define _PAGEOFFSET_HPP #include <fstream>
#include <sstream>
#include <vector>
#include <string>
#include <utility>
#include <stdlib.h>
#include <stdio.h>
using namespace std; class PageOffset
{
public:
PageOffset(string &path)
{
ifstream ifs(path.c_str(),ios::in);
string line;
string str;
pair<int,int> p1;
pair<int ,pair<int ,int > > p2;
while(getline(ifs,line),!ifs.eof())
{
istringstream iss(line);
int pos = ;
while(iss>>str)
{
if(pos == )
{
p2.first = atoi(str.c_str());
}
else if(pos == )
{
p1.first = atoi(str.c_str());
}
else if(pos == )
{
p1.second = atoi(str.c_str());
p2.second = p1;
}
pos++;
}
offset.insert(p2);
}
ifs.close();
} pair<int ,int > &operator[](int docid)
{
return offset[docid];
} size_t size() const
{
return offset.size();
}
private:
map<int,pair<int,int> > offset;
};
#endif

测试程序代码如下:

 #include "XMLParser.hpp"
#include "PageOffset.hpp"
#include <fstream>
#include <cstring>
#include <string>
#include <utility>
using namespace std;
int main()
{
ifstream ifs("pages.lib",ios::in);
PageOffset pageoffset("offset.lib");
char *buf = new char[*]; //开缓存空间
pair<int,int> page =(pageOffset)[vec[i]]; //从偏移文件中提取文档相应的offset与size,读出一篇文章
ifs.seekg(page.first,ios::beg); //定位文件起始位置
memset(buf,,*);
ifs.read(buf,page.second); //读取一篇文档
string str(buf); //C风格的字符串转化为C++风格的字符串
XMLParser xmlparser(str); //将文章加入解析器,初始化一个解析器对象
string title = xmlparser.parser("title"); //解析标题
string url = xmlparser.parser("url"); //解析url
string content = xmlparser.parser("content"); //解析内容
delete []buf; //释放缓存空间,防止内存泄露
return ;
}

以上是针对特定格式的文本库进行解析。因此不能给适用于多种场合。

针对特定XML的解析器XMLParser的更多相关文章

  1. PHP XML Expat 解析器

    PHP XML Expat 解析器 内建的 Expat 解析器使在 PHP 中处理 XML 文档成为可能. XML 是什么? XML 用于描述数据,其焦点是数据是什么.XML 文件描述了数据的结构. ...

  2. XML实体解析器的作用

    XML实体解析器的作用 什么是实体解析器 如果一个sax解析器需要实现对外部实体的自定义处理,那么必须实现一个EntityResolver接口并且注册到SAX驱动上. 从这段文字可以看出来,实体解析器 ...

  3. Mybatis源码解析,一步一步从浅入深(三):实例化xml配置解析器(XMLConfigBuilder)

    在上一篇文章:Mybatis源码解析,一步一步从浅入深(二):按步骤解析源码 ,中我们看到 代码:XMLConfigBuilder parser = new XMLConfigBuilder(read ...

  4. Spring MVC Xml视图解析器

    XmlViewResolver用于在xml文件中定义的视图bean来解析视图名称.以下示例演示如何在Spring Web MVC框架使用XmlViewResolver. XmlViewResolver ...

  5. Spring MVC-视图解析器(View Resolverr)-XML视图解析器(Xml View Resolver)示例(转载实践)

    以下内容翻译自:https://www.tutorialspoint.com/springmvc/springmvc_xmlviewresolver.htm 说明:示例基于Spring MVC 4.1 ...

  6. Rails 4.0 移除了 XML 参数解析器。若要使用请加入 actionpack-xml_parser

    拜读了用 Rails 搭建微信公众平台 API之后发现, params[:xml]这个办法在Rails 4里面已经被办掉了,于是就看了一下Rails 4的新特性发现XML Parameter pars ...

  7. Spring MVC视图解析器

    Spring MVC提供的视图解析器使用ViewResolver进行视图解析,实现浏览器中渲染模型.ViewResolver能够解析JSP.Velocity模板.FreeMarker模板和XSLT等多 ...

  8. 高性能Java解析器实现过程详解

    如果你没有指定数据或语言标准的或开源的Java解析器, 可能经常要用Java实现你自己的数据或语言解析器.或者,可能有很多解析器可选,但是要么太慢,要么太耗内存,或者没有你需要的特定功能.或者开源解析 ...

  9. Spring MVC之视图解析器

    Spring MVC提供的视图解析器使用ViewResolver进行视图解析,实现浏览器中渲染模型.ViewResolver能够解析JSP.Velocity模板.FreeMarker模板和XSLT等多 ...

随机推荐

  1. awk练习题-v参数

    [xxxx.com]a=123bsas=sa2asd=a12ip=ip123[ooo.com]asd12=1223ip=ip123xas=123[xxoo.cn]asas=123sip=xs12213 ...

  2. 如何在eclipse中配置反编译工具JadClipse

    Q:为什么有必要在开发环境中配置反编译工具呢? A:  当运行引用了第三方jar包项目时,突然报出了jar包中的某个类的某一行出现异常.我们想看一下这个class文件的代码时,经常出现了如下图所示的场 ...

  3. ferror,clearerr和EOF含义

    1.我们并不是实时操纵文件,也不是实时生效,它依赖于缓冲区.非缓冲模式编程与常规区别,就是实时与不实时的区别. 2.//fgetc fputc, fgets fputs, fgetwc fputwc, ...

  4. R语言-图形初阶

    在本节中,主要目的是如何使用R语言做出简单的图形 案例1:做出wt和mpg之间的关系 attach(mtcars) plot(wt,mpg) abline(lm(mpg~wt)) title('Reg ...

  5. the first simple html page generated by div and table tags

          <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w ...

  6. 浅谈JavaScript的事件(事件处理程序)

    事件就是用户或者浏览器自身执行的某种动作.诸如click.load和mouseover,都是事件的名字.而响应某个事件的函数就叫事件处理程序.事件处理程序的名字以"on"开头,比如 ...

  7. POJ 2311 Cutting Game [Multi-SG?]

    传送门 题意:n*m的纸片,一次切成两份,谁先切出1*1谁胜 Multi-SG? 不太一样啊 本题的要求是后继游戏中任意游戏获胜就可以了.... 这时候,如果游戏者发现某一单一游戏他必败他就不会再玩了 ...

  8. BZOJ 1770: [Usaco2009 Nov]lights 燈 [高斯消元XOR 搜索]

    题意: 经典灯问题,求最少次数 本题数据不水,必须要暴搜自由元的取值啦 想了好久 然而我看到网上的程序都没有用记录now的做法,那样做遇到自由元应该可能会丢解吧...? 我的做法是把自由元保存下来,枚 ...

  9. Oracle-11g 中使用表空间透明数据加密(TDE)

    Oracle-11g 中使用表空间透明数据加密(TDE)的限制 TDE 表空间加密方式会在数据读写过程中加解密数据.与在 SQL 层面做加解密的 TDE 列加密方式相比,其限制要大幅减少.例如:数据类 ...

  10. Ubuntu下Nginx启动、停止等常用命令

    本文详细介绍Ubuntu下Nginx启动.停止等常用命令.在开发过程中,我们会经常的修改Nginx的配置文件,每次修改配置文件都可以先测试下本次修改的配置文件是否正确,可以利用以下命令: servic ...