一、建立网页库和偏移文件
为文本搜索引擎建立网页库,首先要把所有的网页(这里是文章)格式化,并保存到指定的格式中。如以下格式:
|
|
|
|
|
|
|
|
| ...
|
| ...
其中
如何生成这样的格式呢?对每一篇文章使用以下方法:
首先从文章中提取标题 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进行解析。
以下是解析器的代码:
1 #ifndef _XMLPARSER_HPP
2 #define _XMLPARSER_HPP
3 #include <stdio.h>
4 #include <utility>
5 #include <string>
6 #include <stdlib.h>
7 using namespace std;
8 class XMLParser
9 {
10 public:
11 XMLParser(string & page)
12 :page_(page)
13 {}
14 string parser(string tag)
15 {
16 string ltag,rtag;
17 ltag = "<"+tag+">"; //拼接左标签
18 rtag = "</"+tag+">"; //拼接右标签
19 string str;
20 //pair<string,string> pr;
21 string::size_type bpos;
22 string::size_type epos;
23 string::size_type len;
24 //确定字符串范围
25 bpos = page_.find(ltag);//查找作标签下标
26 epos = page_.find(rtag);//查找右标签下标
27 bpos+=ltag.size();
28 len = epos - bpos; //计算标签包含内容长度
29 if(bpos==page_.npos||epos==page_.npos)
30 {
31 printf("No such tag: %s n",tag.c_str());
32 exit(-1);
33 }
34 if(bpos==epos)
35 {
36 printf("标签内容不存在n");
37 exit(-1);
38 }
39
40 string content = page_.substr(bpos+1,len-2);//截取标签包含内容
41 #if 0
42 if(content[content.size()-1]=='n')
43 content[content.size()-1]==' ';
44 if(content[content.size()-2]=='n')
45 content[content.size()-2]==' ';
46 if(content[content.size()-3]=='n')
47 content[content.size()-3]==' ';
48 #endif
49 //pr.first = tag;
50 //pr.second = content;
51 //return pr; //最好使用std::move,减少复制
52 return content;
53 }
54 private:
55 string &page_; //使用引用,避免大复制
56 };
57 #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 = 0;
while(iss>>str)
{
if(pos == 0)
{
p2.first = atoi(str.c_str());
}
else if(pos == 1)
{
p1.first = atoi(str.c_str());
}
else if(pos == 2)
{
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
View Code
测试程序代码如下:
1 #include "XMLParser.hpp"
2 #include "PageOffset.hpp"
3 #include <fstream>
4 #include <cstring>
5 #include <string>
6 #include <utility>
7 using namespace std;
8 int main()
9 {
10 ifstream ifs("pages.lib",ios::in);
11 PageOffset pageoffset("offset.lib");
12 char *buf = new char[1024*1024]; //开缓存空间
13 pair<int,int> page =(pageOffset)[vec[i]]; //从偏移文件中提取文档相应的offset与size,读出一篇文章
14 ifs.seekg(page.first,ios::beg); //定位文件起始位置
15 memset(buf,0,1024*1024);
16 ifs.read(buf,page.second); //读取一篇文档
17 string str(buf); //C风格的字符串转化为C++风格的字符串
18 XMLParser xmlparser(str); //将文章加入解析器,初始化一个解析器对象
19 string title = xmlparser.parser("title"); //解析标题
20 string url = xmlparser.parser("url"); //解析url
21 string content = xmlparser.parser("content"); //解析内容
22 delete []buf; //释放缓存空间,防止内存泄露
23 return 0;
24 }
以上是针对特定格式的文本库进行解析。因此不能给适用于多种场合。
原文链接: https://www.cnblogs.com/houjun/p/4866913.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/222894
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!