您的位置:首页 > 其它

基于容器的文本操作程序

2010-04-16 14:26 260 查看
C++ STL中定义了许多容器类以及一系列泛型算法,使我们可以更简洁、抽象和有效地编写程序,这样我们就不用把时间花费在那些繁琐的细节上(如内存管理),而把主要的精力放在要解决的实际问题上。针对容器这部分内容的学习,最好的方法莫过于用其来解决一个生活中实际的问题了。STL中介绍的几种容器都各有自己的特点,因此在解决实际问题的时候,应当考虑哪种容器更适合来解决这个问题。

本文基于容器设计一个文本操作类TextQuery Class,程序是Win32 Console Application。

由于时间原因,只实现了几个基本的功能:

(1) 输入某一字符串,查询其是否在文件中存在,若存在则输出行号及此行内容。

(2) 输入某一行号,查询此行的内容。

(3) 分别输入一个文件中已有的字符串和一个想要替换的字符串,完成文本替换。

(4) 输出显示当前的文本内容。

(5) 设计一个菜单的选择模式与用户进行交互。

程序仍需改进的地方有:

(1) 实现基于字符的串匹配算法,可以参考库函数strstr的实现。

(2) 增添两种可区分字母大小写的模式。

(3) 基于需求,实现更多的功能。

(4) 参考泛型算法,简化和优化代码。

PS: 程序中还存在许多需要完善的地方,如果您发现代码中存在问题,恳请您批评指正。Thx !



程序初版代码

2010-4-16

TextQuery.h

// TextQuery.h
// 2010-4-16 wcdj
#ifndef TEXTQUERY_H
#define TEXTQUERY_H
#include <vector>
#include <set>
#include <map>
#include <string>
#include <fstream>
using std::string;
using std::vector;
using std::map;
using std::set;
using std::ifstream;
// typedef to make declarations easier
typedef vector<string>::size_type line_no;
class TextQuery
{
public:
	// constructor
	TextQuery(){};
	// destructor
	~TextQuery(){};
	/* interface:
	 *      read_file builds internal data structures for the given file
	 *      run_query finds the given word and returns set of lines on which it appears
	 *      text_line returns a requested line from the input file
	*/
	void read_file(ifstream &is);
	set<line_no> run_query(const string&) const;
	string text_line(line_no) const;
	// add some new function
	// replace some word to another one
	void replace_word(const string& filename, const string& strTo, const string& strFrom);
	void show_all_text() const;
	void show_help() const;
private:
	// utility functions used by read_file
	void store_file(ifstream&);// store input file
	void build_map();// associated each word with a set of line numbers
	// remember the whole input file
	vector<string> lines_of_text;
	// map word to set of the lines on which it occurs
	map<string, set<line_no>> word_map;
};
#endif



TextQuery.cpp

// TextQuery.cpp
// 2010-4-16 wcdj
#include "stdafx.h"
#include "TextQuery.h"
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <map>
#include <set>
#include <fstream>
using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;
using std::map;
using std::set;
using std::ifstream;
using std::ofstream;
using std::istringstream;
using std::pair;
// typedef to make declarations easier
typedef vector<string>::const_iterator itVecType;
typedef pair<map<string, set<line_no> >::iterator, bool> rPairType;
typedef map<string, set<line_no> >::const_iterator itMapType;
typedef set<line_no>::const_iterator itSetType;
// store input file
void TextQuery::store_file(ifstream& ifs)
{
	string line;
	while(getline(ifs,line))
	{
		lines_of_text.push_back(line);
	}
}
// associated each word with a set of line numbers
void TextQuery::build_map()
{
	// check
	if (lines_of_text.empty())
	{
		cout<<"the file is empty, do not to query! "<<endl;
		return;
	}
	// build map object	
	itVecType sciter=lines_of_text.begin();
	rPairType res;
	set<line_no> lnset;
	line_no ln=1;
	string word;	
	for (;sciter!=lines_of_text.end();++sciter,++ln)
	{
		istringstream iss(*sciter);
		while (iss>>word)
		{
			/* error
			res=word_map.insert(make_pair(word,lnset(ln)));
			if (!res.second)
			{
			
			}
			*/
			// ok, the above sentences can be replaced by the following  one sentence
			word_map[word].insert(ln);
		}
	}
}
// read_file builds internal data structures for the given file
void TextQuery::read_file(ifstream &is)
{
	store_file(is);
	build_map();
}
// run_query finds the given word and returns set of lines on which it appears
set<line_no> TextQuery::run_query(const string& str) const
{
	set<line_no> lnset;
	// search
	itMapType iter=word_map.find(str);
	if (iter==word_map.end())
	{
		return lnset;
	} 
	else
	{
		return iter->second;
	}
}
// text_line returns a requested line from the input file
string TextQuery::text_line(line_no ln) const
{
	string str;
	// check
	if (ln<0 || ln>lines_of_text.size())
	{
		return str;
	} 
	else
	{
		itVecType iter=lines_of_text.begin();
		return *(iter+ln-1);
	}
}
// new function
// replace some word to another one
/* there is a problem in this solution!
 * can not deal with more than one blank
*/
void TextQuery::replace_word(const string& filename, const string& strTo, const string& strFrom)
{
	// call run_query first
	set<line_no> lnset=this->run_query(strFrom);
	// check
	if (lnset.empty())
	{
		cout<<"there is no word [ "<<strFrom<<" ] in this file!"<<endl;
		return;
	} 
	itSetType iter=lnset.begin();
	// process each line to replace
	for (;iter!=lnset.end();++iter)
	{
		istringstream iss(lines_of_text[*iter-1]);
		string word;
		// temporary vector to hold a new line
		vector<string> tmpvec;// in each loop, the vector is clean
		while (iss>>word)// get each word in current line
		{
			if (word==strFrom)
			{
				tmpvec.push_back(strTo);
			}
			else
			{
				tmpvec.push_back(word);
			}
		}
		// save new line
		// error
		//lines_of_text[*iter-1].replace(lines_of_text[*iter-1].begin(),lines_of_text[*iter-1].end(),tmpvec.begin(),tmpvec.end());
		string tmp;
		for (itVecType it=tmpvec.begin();it!=tmpvec.end();++it)// vector to string
		{
			tmp.append(*it+" ");
		}
		lines_of_text[*iter-1]=tmp;
	}
	// write new data into file
	ofstream ofs(filename.c_str());
	for (itVecType it=lines_of_text.begin();it!=lines_of_text.end();++it)
	{
		ofs<<*it<<"/n";
	}
}
// print all text as line
void TextQuery::show_all_text() const
{
	// check
	if (lines_of_text.empty())
	{
		cout<<"the file is empty! "<<endl;
		return;
	}
	// print all
	itVecType iter=lines_of_text.begin();
	line_no ln=1;
	for (;iter!=lines_of_text.end();++iter,++ln)
	{
		cout<<ln<<": "<<*iter<<endl;
	}
}
// show help information
void TextQuery::show_help() const
{
	cout<<endl<<"/t======================================="<<endl;
	cout<<"/tchoose the number of one option you wanna do"<<endl;
	cout<<"/t[1] enter a word and print the line number on which it is"<<endl;
	cout<<"/t[2] enter a number of line to print the contents of this line"<<endl;
	cout<<"/t[3] enter an old word and a new word to complete replacing"<<endl;
	cout<<"/t[4] show all the contents of the file right now"<<endl;
	cout<<"/tNote: press q or Ctrl+Z to quit this program"<<endl;
	cout<<"/t======================================="<<endl;
}



main.cpp

/*
// 2010-4-16 wcdj
f.txt:
wcdj is a guy , he is from LuoYang HeNan province .
C++ is a computer language, and java also is .
Today is Tuesday , I will go out for dinner soon .
Kind regards to everybody .
*/
#include "stdafx.h"
#include <iostream>
#include <string>
#include <fstream>
#include <stdexcept>// runtime_error
#include "TextQuery.h"
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
	cout<<"/tWelcome to using TextQuery system"<<endl;
	cout<<"/t Leftright: wcdj 2010-4-16"<<endl<<endl;
	cout<<"Enter file name you wanna query: ";
	string filename;
	cin>>filename;
	ifstream ifs(filename.c_str());
	// check
	if (!ifs)
	{
		cerr<<"error: unable to open input file: "<<filename<<endl;
		system("pause");
		return EXIT_FAILURE;// 1
	}
	// build map
	TextQuery myQy;
	myQy.read_file(ifs);// builds internal data structures for the given file
	while (1)
	{
		// give a note
		myQy.show_help();
		string choose;
		cin>>choose;
		if (!cin || choose=="q" || choose=="Q")
		{
			break;
		}
		int nchoose=atoi(choose.c_str());
		if (nchoose<=0 || nchoose>4)
		{
			cout<<"please choose right number of option!"<<endl;
			continue;// again
		}
		switch (nchoose)
		{
		case 1:
			// search word and print the line number on which it is
			while (1)
			{
				cout<<"Enter a word you wanna search (press q or Ctrl+Z to quit): ";
				string word;
				cin>>word;
				if (!cin || word=="q" || word=="Q")
				{
					break;
				}
				set<line_no> rlnSet=myQy.run_query(word);	
				if (rlnSet.empty())
				{
					cout<<"there is no word [ "<<word<<" ] in this file! "<<endl;
				} 
				else
				{
					cout<<"find word [ "<<word<<" ]: "<<endl;
					// print line number and corresponding text
					set<line_no>::const_iterator iset=rlnSet.begin();
					for (;iset!=rlnSet.end();++iset)
					{
						cout<<*iset<<": "<<myQy.text_line(*iset)<<endl;
					}
				}
			}
			cin.clear();
			break;
		case 2:
			// enter a number of line to print the contents of this line
			while (1)
			{
				cout<<"Enter a number of line you wanna search (press Ctrl+Z to quit): ";
				//line_no ln;
				int ln;
				cin>>ln;
				if (!cin.eof())
				{
					// input stream is corrupted; bail out
					if (cin.bad())
					{
						throw runtime_error("IO stream corrupted");
					}
					// bad input
					if (cin.fail())
					{
						cerr<<"bad data, try again!"<<endl;// warn the user
						//cin.clear(istream::failbit);// error, can not reset the stream, I don't know why
						cin.clear();// ok, reset the stream
						// Note: get rid of the illegal input in the buffer
						int ch=0;
						while ((ch=getchar())!='/n' && ch!=EOF);
						continue;// get next input
					}
				}
				else// press Ctrl+Z
				{
					break;
				}
				if (ln<=0)
				{
					cerr<<"the number of line must be more than 0!"<<endl;
					continue;// enter again
				}
				string rstr=myQy.text_line(ln);
				if (rstr.empty())
				{
					cout<<"there is no content in this line [ "<<ln<<" ] "<<endl;
				} 
				else
				{
					cout<<"the contents in this line [ "<<ln<<" ]: "<<endl;
					// print
					cout<<ln<<": "<<rstr<<endl;
				}
			}
			cin.clear();
			break;
		case 3:
			{
				// enter an old word and a new word to complete replacing some word to another one in the file
				cout<<"Enter a wordFrom and a wordTo respectively: ";
				string wordFrom,wordTo;
				cin>>wordFrom>>wordTo;
				myQy.replace_word(filename,wordTo,wordFrom);
				// build again
				myQy.read_file(ifs);// builds internal data structures for the given file
				break;
			}
		case 4:
			// show all the contents of the file
			myQy.show_all_text();
			break;	
		default:
			NULL;
		}
	}
	
	system("pause");
	return EXIT_SUCCESS;// 0
}




2010-4-16 wcdj
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: