词典

英汉词典

文章目录

  • 英汉词典
    • 一.引言
    • 二.资源链接
    • 三.代码
      • 1.方法一:一次性将文件读入字符串
        • ①分析
        • ②代码
      • 2.方法二:map容器
        • ①分析
        • ②代码
      • 3.方法三:单串数据库
        • ①分析
        • ②代码
          • Ⅰ.精确查询
          • Ⅱ.模糊查询
    • 四.解析数据小练习

一.引言

​ 最近在学字符串,学了如何解析数据,下面就来尝试一下用C++字符串实现英汉词典的搜索功能吧。

​ 实现了这个,没有网络也能快速查词噢!

二.资源链接

​ 我这篇文章用的是一个txt文件,点击百度云链接领取文件==(提取码:C415)==,然后操作的时候我把这个txt文件和我的cpp文件放在一个文件夹里面。

词典_第1张图片

​ (词典截图)

看到这页截图,是不是十分眼熟呢,每次背单词都从abandon开始背起,但也就熟悉a开头的那些,单词书的后面是崭新的,快要考六级了,一点也不慌(bushi)

三.代码

1.方法一:一次性将文件读入字符串

①分析

​ 观察上面词典的字符串形式 先是单词,然后是空格,然后是释义。查词的过程中,我们要输入的单词是一个字符串,那检索的时候就是判断字符串相等的过程。

​ 那么用几个常用的函数就可以实现了, find()查找空格,然后substr()取出前面的单词,再与输入的单词对比


​ 但是这个程序也有弊端,因为频繁的使用硬盘读写,效率低,损耗大。

②代码

#include
#include
#include//字符串流
#include
using namespace std;
class test
{
     
private:
    ifstream f; //文件句柄
    string s,S; //S是整个一行 s是取出的字串:单词
    string word;//word是用户输入的所需查询的单词
    string::size_type n;//n是第一个空格的位置
public:
    test()
    {
     
        f.open("英汉词典.txt",ios::in);//in和out是针对程序而言的,要读文件,把文件读进来,读到程序里来
        if(!f)
        {
     
            cout<<"file open error!"<<endl;
        }
    }
    void dict()
    {
     
        cout<<"input a word:";
        cin>>word;
        while(!f.eof())
        {
     
            getline(f,S);//getline读一行,此函数可读取整行,包括前导和嵌入的空格,并将其存储在字符串对象中。
            
            n=S.find(" ",0);
            s=S.substr(0,n);
            if(s==word)
            {
     
                cout<<S<<endl;
            }

        }
    }
    ~test()
	{
     
		f.close();
	}
};

int main()
{
     
    test t;
    t.dict();
    return 0;
}

2.方法二:map容器

①分析

​ map容器非常擅长检索,用map容器实现词典功能,一次性将文件读入了容器(内存),将磁盘操作转换为内存操作,减少了损耗,且十分高效。

​ 把单词作为map的key,把单词以及释义那一整行作为map的value。

②代码

#include
#include
#include
#include
#include
#include
#include

using namespace std;
class test
{
     
private:
    ifstream f;
    string S,word,s;
    string::size_type n;
    map<string,string>a;
    map<string,string>::iterator p;
public:
    test()
    {
     
        f.open("英汉词典.txt",ios::in);
        if(!f)
        {
     
            cout<<"file open error!"<<endl;
        }
        else
        {
     
            while(!f.eof())
            {
     
                getline(f,S);
                n=S.find(" ",0);
                s=S.substr(0,n);
                a.insert(pair<string,string>(s,S));
            }
            
        }
    }
    void dict()
    {
     
        cout<<"input a word:";
        cin>>word;
        p=a.find(word);
        if(p!=a.end())
        {
     
            cout<<p->second<<endl;
        }
        else
        {
     
            cout<<"no record"<<endl;
        }
    }
    ~test()
	{
     
		f.close();
	}
};

int main()
{
     
    test t;
    t.dict();
    return 0;
}

3.方法三:单串数据库

①分析

​ 把整个文件一次性读入一个字符串,精确查询的效率比方法一更高,但没有容器效率高,操作简洁,可以实现模糊查询(方法二map只能键值)

​ 用#分隔每个词条,不要用“-”来分搁,因为有如by-product这种单词

②代码

Ⅰ.精确查询
#include
#include
#include
#include
using namespace std;
class test
{
     
private:
    ifstream f;
    string s;//#单词#
    string s1;//提取单词,与输入的进行比较
    string ss;//单词+释义
    string word;//输入的词
    string::size_type n1,n2,n3; //定位
    string::size_type pos;//迭代变量
public:
    test()
    {
     
        f.open("英汉词典.txt",ios::in);
        if(!f)
        {
     
            cout<<"file open error!"<<endl;
            exit(0);
        }
        else
        {
     
            s="#";
            while(!f.eof())
            {
     
                getline(f,ss);
                s=s+ss+"#";//#词条#词条#词条...词条#
            }
        }
    }
    void dict()
    {
     
        cout<<"input a word:";
        cin>>word;
        pos=0;
        while(true)
        {
     
            if(s.find(word,pos)!=string::npos)
            {
     
                n1=s.find(word,pos);//word本身就是字符串了,不要加“”,
                n1=s.rfind("#",n1);//可能出现查找on,但是y有的单词比如moon里面有on这种情况,所有要rfind #
                n2=s.find(" ",n1);
                n3=s.find("#",n1+1);
                s1=s.substr(n1+1,n2-n1-1);
                ss=s.substr(n1+1,n3-n1-1);
                if(s1==word)
                {
     
                    cout<<ss<<endl;//输出词条
                    break;//找到了就不用继续找了
                }
                pos=n3;
            }
        }
    }
    ~test()
    {
     
        f.close();
    }
};
int main()
{
     
    test t;
    t.dict();
    return 0;
}
Ⅱ.模糊查询
#include
#include
#include
#include
using namespace std;
class test
{
     
private:
    ifstream f;
    string s;//#单词#
    string s1;//提取单词,与输入的进行比较
    string ss;//单词+释义
    string word;//输入的词
    string::size_type n1,n2,n3; //定位
    string::size_type pos;//迭代变量
public:
    test()
    {
     
        f.open("英汉词典.txt",ios::in);
        if(!f)
        {
     
            cout<<"file open error!"<<endl;
            exit(0);
        }
        else
        {
     
            s="#";
            while(!f.eof())
            {
     
                getline(f,ss);
                s=s+ss+"#";//#词条#词条#词条...词条#
            }
        }
    }
    void dict()
    {
     
        cout<<"input a word:";
        cin>>word;//输入英文中文都可以
        pos=0;
        while(true)
        {
     
            if(s.find(word,pos)!=string::npos)
            {
     
                n1=s.find(word,pos);//word本身就是字符串了,不要加“”,
                n1=s.rfind("#",n1);
                n3=s.find("#",n1+1);
                ss=s.substr(n1+1,n3-n1-1);
				//不需要找空格了,直接把含有你所输入的模糊word那一个夹在两个#之间的词条输出来
                cout<<ss<<endl;
                pos=n3;
            }
        }
    }
    ~test()
    {
     
        f.close();
    }
};
int main()
{
     
    test t;
    t.dict();
    return 0;
}


四.解析数据小练习

方法三中用到了解析数据的方法,这个东西熟练一点就会了,以下为和我一样的初学者提供几个解析数据的小练习


①从键盘输入一个形如“-s1-s2-s3-”的字符串,将该字符串分解为三个子串s1、s2、s3,并且输出这三个子串。

(s1、s2、s3为长度不等、内容不定的字符串) 将解析出来的s1、s2、s3…子串压入容器,通过容器输出其中的所有元素。

#include 
#include 
#include 
using namespace std;
class test
{
     
private:
    string s;
    vector<string>a;
    vector<string>::iterator p;
public:
    test()
    {
     
        s="-da21g-xchyyy8-dsauuo09765-";//随便打字的

    }
    void input()
    {
     
        string::size_type pos,n;
        pos=0;//迭代变量
        while(true)
        {
     
            if(s.find("-",pos)!=string::npos)
            {
     
                pos=s.find("-",pos);
                ++pos;
                n=pos;
                if(s.find("-",pos)!=string::npos)
                {
     
                    pos=s.find("-",pos);
                    a.push_back(s.substr(n,pos-n));

                }
                else
                    break;


            }
            else
                break;
        }

    }
    void browse()
    {
     
        for(p=a.begin();p!=a.end();++p)
        {
     
            cout<<*p<<endl;
        }
    }
};
int main()
{
     
    test s;
    s.input();
    s.browse();

    return 0;
}

void input()那里也可以简化一点

 void input()
    {
     
        string::size_type pos,n;
        pos=0;
        while(true)
        {
     
            if(s.find("-",pos)!=string::npos)
            {
     
                n=s.find("-",pos);
                pos=s.find("-",n+1);
                a.push_back(s.substr(n+1,pos-n-1));

            }
            else
                break;
        }
    }

②建立文本文件“004.txt”,里面内容为“-Zhang-86-Li-92-Wang-75”

建立类(test),类内建立vector容器,容器元素类型为结构体(S),S中有两项数据“name”、“score”,都是字符串类型。

在类中建立一个构造函数,将“004.txt”的内容解析后压入容器

output函数,使用容器输出所有学生数据。

Sort函数,按成绩降序对学生数据进行排序。

在主函数中建立一个对象,依次运行Sort、output函数。

#include 
#include 
#include 
#include
#include
#include
#include
using namespace std;
struct S
{
     
    string name;
    string score;

};
class test
{
     
private:
    ifstream f;
    vector<S>a;
    vector<S>::iterator p;
    string::size_type pos,n;
    string ss;//读取整个字符串
    string s1;//读取名字
    string s2;//读取分数
    S t;
public:
    test()
    {
     
        f.open("004.txt",ios::in);
        getline(f,ss);
        pos=0;
        while(true)
        {
     
            if(ss.find("-",pos+1)!=string::npos)
            {
     
                n=ss.find("-",pos);
                pos=ss.find("-",n+1);
                s1=ss.substr(n+1,pos-n-1);
                t.name=s1;
                n=ss.find("-",pos+1);
                s2=ss.substr(pos+1,n-pos-1);
                t.score=s2;
                a.push_back(t);

                pos=n;


            }
            else break;//没有break退不出来
        }
    }
    static bool cmp(S m1,S m2)
    {
     
        return m1.score>m2.score;
    }
    void Sort()
    {
     
        sort(a.begin(),a.end(),cmp);
    }
    void output()
    {
     
        for(p=a.begin();p!=a.end();++p)
        {
     

            cout<<p->name<<"——"<<p->score<<endl;
        }
    }
    ~test()
    {
     
        f.close();
    }

};
int main()
{
     
    test t;
    t.Sort();
    t.output();
    return 0;
}


我遇到的bug:

一是一开始忘了break

二是我原本是ss.find("-",pos),没有用pos+1,而pos最后赋值为n-1

结果解析完那些数据之外多输出了一个"–"是因为最后一次if判断仍然能进行,而找到最后一个“-”之后,后面已经取不出子串了

于是调整,最后一次if判断直接从最后一个"-"后面一个位置开始找,肯定找不到“-“了,于是就else break了

  while(true)
        {
     
            if(ss.find("-",pos+1)!=string::npos)
            {
     
                n=ss.find("-",pos);
                pos=ss.find("-",n+1);
                s1=ss.substr(n+1,pos-n-1);
                t.name=s1;
                n=ss.find("-",pos+1);
                s2=ss.substr(pos+1,n-pos-1);
                t.score=s2;
                a.push_back(t);

                pos=n;


            }
            else break;//没有break退不出来
  		}

但我也产生了一个疑问,上面这段代码在最后字符串结束了还在取子串,为啥不报错呢?

我先用个小程序试验了下,取不到东西果真没报错,但前面还是把空的东西压入了容器,在遍历的时候输出了"–"

词典_第2张图片

**小tips:**原先我在遍历那里是cout所以以后可以自行输出一些东西来检查程序!

所以还是用n+1干脆!

注意:因为给的几个分数位数相同所以可以直接字符串ascll码

比较,如果有92分还有101分比较,就要转化成数字比较了,不然排序排出来92比101大


另外,构造函数那里解析数据还可以清晰一点(感觉变量适当多设一点,更清晰)

#include 
#include 
#include 
#include 
#include 
using namespace std;
struct S
{
     
	string name;
	string score;
};
class test
{
     
private:
	string s;
	string::size_type n1,n2,n3,pos;
	vector<S>a;
	vector<S>::iterator p;
	ifstream f;
	S t;
public:
	test()
	{
     
		f.open("004.txt",ios::in);
		getline(f,s);
		f.close();
		pos=0;
		while(true)
		{
     
			if(s.find("-",pos+1)!=string::npos)//==string::npos表示没找到 !=就是找到了
			{
     
				pos=s.find("-",pos);
				n1=pos;
				n2=s.find("-",n1+1);
				n3=s.find("-",n2+1);
				t.name=s.substr(n1+1,n2-n1-1);
				t.score=s.substr(n2+1,n3-n2-1);
				a.push_back(t);
				pos=n3;
			}
			else break;
		}
	}
	static bool cmp(S s1,S s2)
	{
     
		return s1.score>s2.score;
	}
	void browse()
	{
     
		for(p=a.begin();p!=a.end();++p)
		{
     
			cout<<p->name<<"-"<<p->score<<endl;
		}
	}
	void Sort()
	{
     
		sort(a.begin(),a.end(),cmp);
	}
};
int main()
{
     
	test t;
	t.Sort();
	t.browse();
	system("pause");
	return 0;
}


③学生成绩检索:

每名同学有三项数据:学号、姓名、成绩,放在一个字符串中。以三名同学的数据为例,串的内容为:

“-001-Wang-95-002-Li-98-003-Liu-98-”

其中001、002、003代表学号。

要求,从键盘输入某同学的学号,通过对字符串的处理,分割出该同学的三项数据并且分行输出。然后将这三项数据用分隔符“-”连接在一起写入文本文件“003.txt”中。

#include 
#include 
#include 
#include
#include
#include
#include
using namespace std;
class test
{
     
private:
    ofstream f;
    string S="-001-Wang-95-002-Li-98-003-Liu-98-";
    string num;//学号
    string name;//姓名
    string score;//分数
    string ss;//三项数据连在一起
    string::size_type n1,n2,n3,n4;
    string seek;//用户要查找的
public:
    test()
    {
     
            cout<<"input num:";
            cin>>seek;
            n1=S.find(seek,0);
            cout<<seek<<endl;
            n2=S.find("-",n1);
            n3=S.find("-",n2+1);
            name=S.substr(n2+1,n3-n2-1);
            cout<<name<<endl;
            n4=S.find("-",n3+1);
            score=S.substr(n3+1,n4-n3-1);
            cout<<score<<endl;
            ss="-"+seek+"-"+name+"-"+score+"-";
            ofstream f("003.txt",ios::out);
            if(f)
            {
     
                f<<ss<<endl;
                f.close();
            }
    }
};

int main()
{
     
    test t;


    return 0;
}


当然也可以用前面英汉词典用到的那个rfind

#include
#include 
#include 
#include 
using namespace std;
class test
{
     
private:
	string s,ss,s1,s2,s3;
	ofstream f;
public:
	test()
	{
     
		s="-001-Wang-95-002-Li-98-002-Liu-99-";
		f.open("003.txt",ios::out);
	}
	void input()
	{
     
		cout<<"input a string:";
		cin>>ss;
	}
	void output()
	{
     
		string::size_type n1,n2,n3,n4;
		if(s.find(ss,0)!=string::npos)
		{
     
			n1=s.find(ss,0);
			n1=s.rfind("-",n1);//"-"
			n2=s.find("-",n1+1);//"-"
			n3=s.find("-",n2+1);//"-"
			n4=s.find("-",n3+1);//"-"
		}
		s1=s.substr(n1+1,n2-n1-1);
		s2=s.substr(n2+1,n3-n2-1);
		s3=s.substr(n3+1,n4-n3-1);
		cout<<s1<<endl;
		cout<<s2<<endl;
		cout<<s3<<endl;
		f<<s1+"-"+s2+"-"+s3<<endl;
	}
	~test()
	{
     
		f.close();
	}
};
int main()
{
     
	test t;
	t.input();
	t.output();
	return 0;
}



你可能感兴趣的:(C++入门,数据库,c++,字符串)