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;
}
程式運作結果為:
關鍵的地方看注意即可, 沒有太複雜的代碼
來看下面這種寫法:
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裡的内容:
程式的運作結果為:
注意, 将':'指定為分界字元後, 換行符将被視為正常字元, 是以檔案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函數
來看運作結果:
最後如果我們有一個string對象, 但是需要c風格字元串我們可以使用c_str()方法例如:
string filename;
cout << "Enter file name: ";
cin >> filename;
ofstream fout;
fout.open(filename.c_str());
c_str()方法傳回一個指向C-風格字元串的指針.