针对特定XML的解析器XMLParser
2015-10-10 15:01
267 查看
一、建立网页库和偏移文件
为文本搜索引擎建立网页库,首先要把所有的网页(这里是文章)格式化,并保存到指定的格式中。如以下格式:
|
| <doc>
| <docid>...</docid>
| <url>...</url>
| <title>...</title>
| <content>...</content>
| </doc>
| <doc>
| ...
| </doc>
| ...
其中<doc>……</doc>保存着一篇文章;<docid>...</docid> 保存文档id;<url>...</url>保存文本路径;<content>...</content> 保存文章内容。
如何生成这样的格式呢?对每一篇文章使用以下方法:
首先从文章中提取标题 title;以及获得文章的路径,然后用字符串拼接,拼接成上述格式。
循环对所有文章执行上面的操作,就得到一个网页库和一个偏移文件。
二、解析网页
根据偏移文件,从网页库中读出一篇网页,接着对网页库中的docid,title,url进行解析。
以下是解析器的代码:
解析器每次只能传入一个标签,并且返回标签对应的内容,要对所有标签进行解析,那么就要多次调用parser()。当然,对于一篇文章,就对应一个解析器对象,parser()是对外的一个函数,接收标签,并从对象中解析出便签包含的内容。也就是说,创建一个对象可以对这个对象调用多次parser(string tag)对文章进行解析。
三、解析器的使用
首先要有一个加载偏移文件的工具,这里写了一个工具PageOffset.hpp
(代码折叠)代码如下:
View Code
测试程序代码如下:
以上是针对特定格式的文本库进行解析。因此不能给适用于多种场合。
为文本搜索引擎建立网页库,首先要把所有的网页(这里是文章)格式化,并保存到指定的格式中。如以下格式:
|
| <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(-1); } if(bpos==epos) { printf("标签内容不存在\n"); exit(-1); } string content = page_.substr(bpos+1,len-2);//截取标签包含内容 #if 0 if(content[content.size()-1]=='\n') content[content.size()-1]=='\0'; if(content[content.size()-2]=='\n') content[content.size()-2]=='\0'; if(content[content.size()-3]=='\n') content[content.size()-3]=='\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 = 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
测试程序代码如下:
#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[1024*1024]; //开缓存空间 pair<int,int> page =(pageOffset)[vec[i]]; //从偏移文件中提取文档相应的offset与size,读出一篇文章 ifs.seekg(page.first,ios::beg); //定位文件起始位置 memset(buf,0,1024*1024); 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 0; }
以上是针对特定格式的文本库进行解析。因此不能给适用于多种场合。
相关文章推荐
- Redis详解:hashes数据类型及操作
- yum简单安装apache
- C语言出错问题汇总【需要更新】
- C语言出错问题汇总【需要更新】
- yum简单安装apache
- 图 ->拓扑排序
- 根据select选项的值,改变css
- intptr_t 其实不是指针类型
- 使用匿名管道
- TinyBlob、Blob、MediumBlob、LongBlob大小
- 编码压缩标准与视频格式
- UITableView绑定不同的cell 的 ID 写法
- jQuery 获取表单元素中值的方法
- html a标签
- parseInt 和parseFloat 区别
- Worm.Win32.DownLoader.ns病毒主进程新式输入法注入分析(IME Inject)
- linux输入子系统(5) - 学习框架
- Linux命令总结【待续】
- Linux命令总结【待续】
- 【springmvc+mybatis项目实战】杰信商贸-33.出口报运修改+报运货物批量展现-批量修改控件2