zoukankan      html  css  js  c++  java
  • 针对特定XML的解析器XMLParser

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

    为文本搜索引擎建立网页库,首先要把所有的网页(这里是文章)格式化,并保存到指定的格式中。如以下格式:
       |                                  
       |    <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进行解析。

    以下是解析器的代码:

     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 
    ",tag.c_str());
    32             exit(-1);
    33         }
    34         if(bpos==epos)
    35         {
    36             printf("标签内容不存在
    ");
    37             exit(-1);
    38         }
    39 
    40         string content = page_.substr(bpos+1,len-2);//截取标签包含内容
    41 #if 0
    42         if(content[content.size()-1]=='
    ')
    43             content[content.size()-1]=='';
    44         if(content[content.size()-2]=='
    ')
    45             content[content.size()-2]=='';
    46         if(content[content.size()-3]=='
    ')
    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 }

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

  • 相关阅读:
    Yet Another Monster Killing Problem
    Element Extermination
    最短路径
    Secret Passwords
    New Year Parties
    Water The Garden
    Zero Quantity Maximization
    Anya and Cubes
    代码规范&《数学之美》读后感
    带负边权的最短路径(有向图)——Bellman-Ford算法
  • 原文地址:https://www.cnblogs.com/houjun/p/4866913.html
Copyright © 2011-2022 走看看