C++学习之第十四天-智能指针shared_ptr的应用-文本查询

代码实现基本是手敲一遍Primer C++第五版12.3文本查询程序设计,写一遍来进行学习巩固。

文本查询程序类的定义

TextQuery类

1.提供一个istream,来读取输入文件。

2.提供一个query操作,接受一个string,返回一个QueryResult对象来表示String出现的那些行。

3.考虑QueryResult对象共享数据的要求,QueryResult类保存单词关联的行号set
    1.三个数据成员:1.要查询的单词    2.单词所对应行号set的智能指针 3.句子的集合vector
    2.一个print函数:打印输出结果


4.类有两个数据成员:
    1.一个指向动态分配的vector的智能指针shared_ptr,vector用来保存文件中的每个句子
    2.一个是容器map<word,shared_ptr>,key为单词,value为智能指针,指针管理行号的集合set
    

知识点须知

1.using line_no = vector<string>::size_type,string中的size_type是个unsigned类型,其长度根据机器的不同而不同,这里相当于给line_no起个别名,ubuntu下,其类型为unsigned long

2.shared_ptr智能指针与map容器配合使用,map(word,shared_ptr<set<line_no>>); key:单词 value:智能指针,该智能指针用来管理一个set,set容器里面存储的是每个单词所在行号的集合。

3.使用C++11 auto来遍历容器的方法

4.map容器的使用
    1.map中find的作用:map.find(sought),查找单词sought,如果存在,返回该单词的迭代器,如果不存在,返回end();
    2.map容器wm的特点,wm[word],若word不在wm中,下标运算会把word添加到wm中,默认初始化value的值,如果value是个指针,则初始化value为空指针
    3.迭代器中的first和second的使用,


5.istringstream流,把string句子分解为单词。

了解map容器的基本使用

必知点:

1.map容器的插入,map容器遇到下标运算符,就会往容器里添加key,value有默认值

2.map容器插入后,自动给key进行排序

3.map容器的遍历。

4.map容器中使用find-返回对应key的迭代器。

#include <iostream>
#include<algorithm>
#include <set>
using namespace std;
#include <map>
#include <vector>
#include <string>

void test01()
{
    map<string, int> vm;
    vm["hello"];//map容器遇到下标运算符就会往容器里添加,value默认值为0
    vm["world"] = 3;
    vm.insert(make_pair("C++",12));//常用的插入方式
    cout<<"遍历方式1:C++11 Auto:"<<endl;
    //map容器的遍历方式1:
    for(auto it: vm)
    {
        cout<< it.first<<":"
            <<it.second<<endl;
    }
    //map容器的遍历方式2:
    cout<<"遍历方式2:"<<endl;
    for(map<string,int>::iterator it = vm.begin();it!=vm.end();it++)
    {
        cout<<it->first<<":"
            <<it->second<<endl;
    }

    cout<<endl<<endl;
    //map.find的使用
    auto it = vm.find("hello");//返回的是对应单词的迭代器
    cout<<it->first<<":"<<it->second<<endl;

    it = vm.find("love");
    bool ret = (it==vm.end());
    cout<<ret<<endl;//如果love不在vm中,返回的迭代器是vm.end()

}
int main()
{
    test01();
    return 0;
}

运行结果

遍历方式1:C++11 Auto:
C++:12
hello:0
world:3
遍历方式2:
C++:12
hello:0
world:3


hello:0        //vm.find("love")在vm中不存在,因此返回的vm.end()
1  //it==vm.end()

文本查询

main.cc

#include "test.h"

void test01()
{
    ifstream is("china_daily.txt");//ifstream文件流读取指定文件
    if(!is.good())//判断有没有读取成功
    {
        cout<<"ifstream is not good"<<endl;
        return;
    }
    TextQuery t1(is);
    QueryResult q = t1.query("with");//查询with单词
    print(cout, q);//打印结果
    
    
}
int main()
{
    test01();
    return 0;
}

test.h

#include <iostream>
#include<fstream>
using namespace std;
#include <sstream>
#include <vector>
#include <map>
#include <set>
#include <memory>
#include <string>
class QueryResult;
class TextQuery
{
public:
    using line_no = vector<string>::size_type;//给vector<string>::size_type起别名
    //size_type:是个unsigned类型,其长度与机器匹配,ubuntu下,为unsigned long类型
    TextQuery(ifstream &);//构造函数,传入文件名
    QueryResult query(const string &)const; //查询
    //class QueryResult;
private:
    shared_ptr<vector<string>> file;//输入文件
    map<string, shared_ptr<set<line_no>>> wm;//一个智能指针管理一个set,wm(string,shared_ptr)
};

class QueryResult
{
	friend ostream& print(ostream &,const QueryResult &);//打印操作
public:
    using line_no = vector<string>::size_type;//给vector<string>::size_type起别名
    QueryResult(string s, shared_ptr<set<line_no>> p,shared_ptr<vector<string>> f)
    :sought(s),lines(p),file(f)
    {
    }
        

private:
    string sought;//用于查询单词
    shared_ptr<set<line_no>> lines;//保存该单词出现的行号
    shared_ptr<vector<string>> file;//用来打印单词所在的句子
};

函数实现部分

test.cc

#include "test.h"
void parseText(string &text)
{
    for(int i=0;i<text.size();i++)
    {
        if(text[i]>='A'&&text[i]<='Z')
        {
            text[i] = tolower(text[i]);
            //text[i]=toupper(text[i]);
            continue;
        }
        if(text[i]>='a'&&text[i]<='z')
        {
            continue;
        }

        text[i]=' ';
        
    }
    //去掉句子首尾空格
    if(!text.empty())
    {
        text.erase(0,text.find_first_not_of(" "));
        text.erase(text.find_last_not_of(" ")+1);
    }
}
//TextQuery构造函数,传入的是一个文件流,
TextQuery::TextQuery(ifstream &is)
:file(new vector<string>)//file是shared_ptr智能指针,用来管理vector<string>容器
 //初始化智能指针file,vector<string>用来保存txt文件中的每个句子
{
    string text;
    while(getline(is,text))//从文件流中读取数据,获取文件中的每一行
    {
        //printf("%p\n",&file);//文件指针的地址,
        file->push_back(text);//把每一行尾插入容器
        int n = file->size()-1; //当前的行号
        parseText(text);        //解析句子,把每一行的标点符号换成空格,去掉首尾的空格,大写变小写
        istringstream line(text);//istringstream流,把文本分解为单词
        string word;
        while(line>>word)
        {
            auto &lines = wm[word];//wm[word],map(word,shared_ptr)
            //map的特点,若word不再wm中,下标运算会把word添加到wm中,默认初始化lines为空指针
            //lines是管理map容器中每个单词行号集合的智能指针,单词第一次出现时要给指针分配一个set;
            if(!lines)//第一次遇到新单词的时候,需要创建管理新set的智能指针
                lines.reset(new set<line_no>);//碰到新单词,给此单词创建一个智能指针,用来管理此单词的行号set
            lines->insert(n);//插入行号
            //printf("%p\n",&lines);//每个单词都有一个智能指针来管理set,打印出来的地址都是不同
        }
    }
}

QueryResult TextQuery::query(const string &sought)const //查询
{
    static shared_ptr<set<line_no>> nodata(new set<line_no>);
    //如果给定的sought没有找到,返回一个空行号set的shared_ptr对象的拷贝。
    auto loc = wm.find(sought);
    //用find而不是下标,避免把单词添加到wm中
    //map中find的作用:查找单词sought,如果存在,返回该单词的迭代器,如果不存在,返回end()
    cout<<loc->first<<endl;//单词
    cout<<loc->second<<endl;//loc->second是管理该单词行号的智能指针,打印出来的会是一个地址
    //把行号打印出来,set存储的是行号的集合
    for(set<line_no>::iterator it = loc->second->begin(); it!=loc->second->end(); it++)
    {
        cout<<*it+1<<" ";
    }
    //使用C++11 auto来遍历
    cout<<endl;
    for(auto it: *loc->second)//loc->second是智能指针,*loc->second是容器本身
    {
        cout<<it+1<<" ";
    }
    cout<<endl;
    if(loc==wm.end())
        return QueryResult(sought,nodata,file);//未找到
    else
        return QueryResult(sought,loc->second,file);//
    
}
string make_plural(size_t ctr,const string &word,const string &ending)
{
    return (ctr>1)?word+ending:word;
}
ostream &print(ostream &os,const QueryResult &qr)
{
    //如果找到了单词,打印出现次数和所有出现的位置
    os<<qr.sought<<" occurs "<<qr.lines->size()<<" "
        <<make_plural(qr.lines->size(),"time","s")<<endl;//大于1为复数+s,小于等于1不加s
    for(auto num: *(qr.lines))//lines是管理单词行号set的智能指针,*(qr.lines)是单词行号的set集合
        os<<"\t(line "<<num+1<<") "
            <<*(qr.file->begin()+num)<<endl;//打印单词所对应的行
        //file->begin()+num即为file指向的vector中第num个位置的元素
        //file是管理vector<string>的智能指针,vector中存的是文件的每一个句子

    return os;
}

运行结果:

with
0x55ccd9caae80     //with单词对应的智能指针的地址
15 24 42 44 60 61 63 71 74 77 87 94 104 //两种遍历行号的打印 
15 24 42 44 60 61 63 71 74 77 87 94 104 
with occurs 13 times
    (line 15) private firms with high growth potential, Gao said.
    (line 24) Bloomberg reported earlier citing people familiar with the matter that the launch 
    (line 42) Chinese travelers like to take instant noodles with them while travelling abroad, 
    (line 44) And the favorite items travelers like to bring with them in their luggage differed 
    (line 60) Quanjude, China's iconic restaurant chain for original Peking roast duck with a 
    (line 61) history since 1864, has embraced the nation's "Internet Plus" strategy, with a new 
    (line 63) "Internet Plus" has sparked integration of the Internet with traditional industries, 
    (line 71) with Quanjude and chairman of a new joint-venture company that is pursuing the online takeout and e-commerce market.
    (line 74) the company, Yage Technology Inc, in October 2015 with Chongqing Kuangcao Technology 
    (line 77) "We believe with our time-honored brand image, experienced artisan cooking skills, 
    (line 87) duck rolls are made in Quanjude restaurants, with the same recipe and ingredients 
    (line 94) according to Yang Aixiang, general manager with Yage Technology.
    (line 104) Yang Xun, a publicist with Baidu Takeout, which handles delivery service of 

猜你喜欢

转载自blog.csdn.net/weixin_49278191/article/details/121308674