天天看點

C++ Primer Plus 書之--C++ string類string類 使用string

string類

先來看個string構造函數的使用示例:

// str1.cpp
#include <iostream>
#include <string>

int main()
{
	using namespace std;
	// string(const char * s)
	string one("Lottery Winner!");
	cout << one << endl;
	string two(20, '$');
	cout << two << endl;
	string three(one);
	cout << three << endl;
	// 使用了重載運算符+=
	one += " Oops!";
	cout << one << endl;
	two = "Sorry ! That was ";
	// 重載[]運算符, 使得可以使用數組表示法來通路string對象中的各個字元
	three[0] = 'p';
	string four;
	four = two + three;
	cout << four << endl;
	char alls[] = "All's well that ends well";
	// 使用alls的前20個字元初始化five對象
	string five(alls, 20);
	cout << five << endl;
	// 構造函數使用begin和end指向的位置之間的值對six進行初始化[begin, end)包括begin, 不包括end
	// alls由于是數組名, 也能看做是位址, 是以這麼寫是沒有問題的
	string six(alls + 6, alls + 10);
	cout << six << endl;
	string seven(&five[6], &five[10]);
	cout << seven << endl;
	// 這個是将four的部分内容複制到構造的對象中
	// 從第8個字元開始, 将16個字元複制到eight中
	string eight(four, 7, 16);
	cout << eight << " in motion!" << endl;
	return 0;
}
           

程式運作結果為:

C++ Primer Plus 書之--C++ string類string類 使用string

關鍵的地方看注意即可, 沒有太複雜的代碼

來看下面這種寫法: 

string seven(five +6, five + 10);
           

由于five是對象名而不是數組名, 是以不會被看做是對象的位址, 是以five不是指針, 是以five+6是沒有異議的, 然而five[6]是一個char值, 是以&five[6]是一個位址, 是以可以被用作該構造函數的參數:

string seven(&five[6], &five[10]);
           

C++11增加了新的構造函數string(initializer_list<cahr> il), 例如:

string piano_man = {'L', 'i', 's', 't', 's'};
string comp_lang = {'s', 't', 's', 'i', 'L'};
           

string版本的getline()函數從輸入中讀取字元, 并将其存儲到目标string中:

string fname;
getline(cin, fname);
           

需要注意的是:

1.到達檔案尾, 在這種情況下, 輸入流的eofbit将被設定, 這意味着方法fail()和eof()都将傳回true;

2.遇到分界字元(預設為\n), 在這種情況下, 将把分界字元從輸入流中删除, 但不存儲它;

3.讀取的字元數大刀最大允許值(string::npos和可供配置設定的記憶體位元組數中較小的一個), 這種情況下, 将設定輸入流的failbit, 也就是fail()将傳回true.

來看一個例子:

#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>

int main()
{
	using namespace std;
	ifstream fin;
	fin.open("test.txt");
	if(fin.is_open() == false)
	{
		cerr << "Can't open file. " << endl;
		exit(EXIT_FAILURE);
	}
	string item;
	int count = 0;
	getline(fin, item, ':');
	while(fin)
	{
		++count;
		cout << count << ": " << item << endl;
		getline(fin, item, ':');
	}
	cout << "Done " << endl;
	fin.close();
	return 0;
}
           

我們來看一下txt裡的内容:

C++ Primer Plus 書之--C++ string類string類 使用string

程式的運作結果為:

C++ Primer Plus 書之--C++ string類string類 使用string

注意, 将':'指定為分界字元後, 換行符将被視為正常字元, 是以檔案test.txt中第一行末尾的換行符将成為包含"cottage cheese"的字元串中的第一個字元. 同樣第二行末尾的換行符是第9個輸入字元串中唯一的内容.

使用string

字元串之間可以進行比較, string類對全部6個關系運算符都進行了重載. 并且string對象和可以與另一個string對象, c風格字元串進行比較, 并能夠将c風格字元串與string對象進行比較:

看一個例子:

string snake1("cobra");
string snake2("coral");
// C風格字元串
char snake3[20] = "anaconda";
// 重載了operator<(const string &, const string &)
if(snake1 < snake2)
	...
// 重載了operator==(const string &, const char *)
if(snake1 == snake3)
	...
// 重載了operator!=(const char *, const string &)
if(snake3 != snake2)
	...
           

同時我們可以擷取字元串的長度, 通過size()和length()成員函數都可以擷取字元串中的字元數:

if(snake1.length() == snake2.size())
	cout << "Both strings have the same length." << endl;
           

還可以在字元串中搜尋給定的字元串或字元:

// 從字元串的pos位置開始, 查找字元串str, 如果找到傳回該字元串首次出現時首字元的索引, 否則傳回string::npos(字元串可存儲的最大字元數)
size_type find(const string & str, size_type pos = 0) cont;
size_type find(const char * s, size_type pos = 0) cont;
// 從字元串的pos位置開始, 查找s的前n個字元組成的子字元串. 如果找到, 傳回該子字元串首次出現時其首字元的索引, 否則, 傳回string::npos
size_type find(const char * s, size_type pos = 0, size_type n);
// 從字元串的pos位置開始, 查找字元ch, 如果找到傳回該字元串首次出現時首字元的索引, 否則傳回string::npos(字元串可存儲的最大字元數)
size_type find(char ch, size_type pos = 0) const
           

string庫還提供了相關的方法: rfind(), find_first_of(), find_last_of(), find_first_not_of() 和 find_last_not_of(). 他們的重載的參數清單都與find()方法相同.

rfind()方法查找子字元串或字元最後一次出現的位置;

find_first_of() 方法在字元串中查找參數中任何一個字元首次出現的位置, 舉個例子:

string snake1 = "cobra";
int where = snake1.find_first_of("hark");
           

這段代碼将傳回r在"cobra"中的位置, 因為這是"hark"中各個字母在"cobra"首次出現的位置.

find_last_of()與此相同, 隻是傳回最後一次出現的位置, 例如:

int where = snake1.find_last_of("hark");
           

傳回的是a在"cobra"中的位置.

find_first_not_of()方法是在字元串中查找第一個不包含在參數中的字元, 例如:

int where = snake1.find_first_not_of("hark");
           

将傳回c在"cobra"中的位置

來看一個完整的例子:

// hangman.cpp
#include <iostream>
#include <string>
#include <cstdlib>
#include <ctime>
#include <cctype>

using std::string;
const int NUM = 26;
const string wordlist[NUM] = {"apiary", "beetle", "cereal", "danger", "ensign", "florid", "garage", "health", "insult", "jackal", "keeper", "loaner", "manage", "nonce", "onset", "plaid", "quilt", "remote", "stolid", "train", "useful", "valid", "whence", "xenon", "yearn", "zippy"};

int main()
{
	using std::cout;
	using std::cin;
	using std::tolower;
	using std::endl;
	// 随機種子
	std::srand(std::time(0));
	char play;
	cout << "Will you play a word game? <y/n> ";
	cin >> play;
	play = tolower(play);
	// 字元串比較
	while(play == 'y')
	{
		string target = wordlist[std::rand() % NUM];
		int length = target.length();
		// 字元串的構造函數, 用'-'初始化length的長度的字元串
		string attempt(length, '-');
		string badchars;
		int guesses = 6;
		cout << "Guess my secret word, It has " << length << " letters, and you guess " << endl;
		cout << "one letter at a time. You get " << guesses << " wrong guesses. " << endl;
		cout << "Your word: " << attempt << endl;
		while(guesses > 0 && attempt != target)
		{
			char letter;
			cout << "Guess a letter: ";
			cin >> letter;
			if(badchars.find(letter) != string::npos || attempt.find(letter) != string::npos)
			{
				cout << "You already guessed that. Try again " << endl;
				continue;
			}
			int loc = target.find(letter);
			if(loc == string::npos)
			{
				cout << "oh, bad guess ! " << endl;
				--guesses;
				badchars += letter;
			} else {
				cout << "Good guess! " << endl;
				attempt[loc] = letter;
				loc = target.find(letter, loc + 1);
				while(loc != string::npos)
				{
					attempt[loc] = letter;
					loc = target.find(letter, loc + 1);
				}
			}
			cout << "Your word: " << attempt << endl;
			if(attempt != target)
			{
				if(badchars.length() > 0)
					cout << "Bad choices : " << badchars << endl;
				cout << guesses << "bad guesses left" << endl;
			}
		}
		if(guesses > 0)
			cout << "That's right!" << endl;
		else
			cout << "Sorry, the word is " << target << endl;
		
		cout << "Will you play another? <y/n>";
		cin >> play;
		play = tolower(play);
	}
	cout << "Bye" << endl;
	return 0;
}
           

程式就是, 先從我們預先設定的單詞清單中随機選取一個單詞, 然後使用者猜這個單詞是什麼, 有6次錯誤的機會, 使用find函數

來看運作結果:

C++ Primer Plus 書之--C++ string類string類 使用string

最後如果我們有一個string對象, 但是需要c風格字元串我們可以使用c_str()方法例如:

string filename;
cout << "Enter file name: ";
cin >> filename;
ofstream fout;
fout.open(filename.c_str());
           

c_str()方法傳回一個指向C-風格字元串的指針.