C++string中有關字符串內容修改和替換的函數淺析
1.assign()
原型:
//string (1)
basic_string& assign (const basic_string& str);
//substring (2)
basic_string& assign (const basic_string& str, size_type subpos, size_type sublen);
//c-string (3)
basic_string& assign (const charT* s);
//buffer (4)
basic_string& assign (const charT* s, size_type n);
//ill (5)
basic_string& assign (size_type n, charT c);
//range (6)
template <class InputIterator>
basic_string& assign (InputIterator first, InputIterator last);
ps:charT是類模板basic_string的第1個參數,指定了字符串中字符的類型。用char實例化basic_string,得到string(可參考在下的“C++ string到底是什麼”)。所以, 在string中,charT就是char。
示例:
#include<iostream>
#include<string>
using namespace std;
int main()
{
string str1("123456");
string str = "123456789";
char* str2 = "abcdef";
str.assign(str1);
cout << str << endl;//123456 可見執行assign()後,str將被重寫
str.assign(str1, 2, 3);
cout << str << endl;//345 從位置2開始的3個字符
str.assign(str1, 1, 20);//超出范圍
cout << str << endl;//23456
cout << str.length() << endl;//5 可見沒有空格
str.assign(str1, 2, str1.npos);//後面介紹npos
cout << str << endl;//3456 從位置2到末尾的字符給str
str.assign(5, 'X');
cout << str << endl;//XXXXX
str.assign(str1.begin(), str1.end() - 1);
cout << str << endl;//12345 從開頭到結尾-1(即倒數第個字符)
//str.assign(str1.begin() + 4, str1.end() - 4);//不能反著來,即試圖將以str1.begin() + 4(5)開頭,以str1.end() - 4(2)結尾的5432給str是不行的
//cout << str << endl; //這樣會出現運行時錯誤
str.assign(str1.begin() + 2, str1.end() - 3);//前後指向同一字符(3),這樣可以
cout << str << endl;//3
str.assign(str1.begin() + 2, str1.end() - 4);//這個卻可以
cout << str << endl;//空行
cout << str.length() << endl;//0
str.assign("abcdefg", 6);
cout << str << endl;//abcdef 將abcdefg的前6個字符給str
str.assign("abcdefg", 20);//超出范圍
cout << str << endl;//abcdefg+亂碼
cout << str.length() << endl;//10 說明將"abcdefg+3個空格"給了str
str.assign(3, 0x41);
cout << str << endl;//AAA 可以使用16進制的ASCII碼 0x41換成10進制是65,是A的ASCII碼
str.assign(str2);
cout << str << endl;//abcdef
str.assign(str2, 2, 3);
cout << str << endl;//cde 對char*型也可以
return 0;
}
以上代碼中有一句
str.assign(str1, 2, str1.npos);
這裡我們解釋npos:
它的定義如下:
std::string::npos
static const size_t npos = -1;
它是size_t類型的最大值,有些編譯器也將它置為string對象的最大容量(按字節算,包括'\0'),而有些編譯器不是,我們在後邊將會看到。
為什麼是最大呢?
-1用反碼存儲(32位),就是32個1,而size_t是無符號整型,所以,32個1的2進制轉化為10進制就是2的32次方-1,即4294967295。
看下面一段驗證代碼:
#include<iostream>
#include<string>
using namespace std;
int main()
{
string str1 = "123456789";
cout << str1.npos << endl;//4294967295
cout << (str1.npos == -1) << endl;//1
cout << str1.max_size() << endl;//4294967294 1073741820(=2^30-4)
return 0;
}
其中,4294967294是VS2013上的結果,可見max_size()不包括'\0',1073741820是CodeBlocks12.11上的結果。
由此,我們可知,str.assign(str1, 2, str1.npos);等價於str.assign(str1, 2, 4294967294);
另外,在C++11中,還有兩個重載的assign()函數,它們的原型分別是:
//initializer list(7)
basic_string& assign (initializer_list<charT> il);
//move (8)
basic_string& assign (basic_string&& str) noexcept;
其中,(7)與list容器有關,而(8)與右值引用和移動語義有關,這裡我們暫不詳述。
對於(8)中的noexcept關鍵字,它聲明了函數不會拋出異常(當然函數不是真的就永遠都不會拋出異常,比如該函數A(聲明為noexcept)中調用了另一個函數B,而函數B中有拋出異常語句,那麼,當我們調用函數A是,就可能拋出異常),由於noexcept不是本文的重點,這裡我們不詳述,有興趣的讀者可以自行查閱資料了解學習相關內容。
2.swap()
原型:void swap (basic_string& str);
只有這一個,要交換就交換整個字符串,這裡沒有針對子串的操作。
不舉例。
3.erase()
原型:
//sequence (1)
basic_string& erase (size_type pos = 0, size_type len = npos);
//character (2)
iterator erase (iterator p);
//range (3)
iterator erase (iterator first, iterator last);
說明:
注意到basic_string& erase (size_type pos = 0, size_type len = npos);給出了默認參數,這樣,我們在使用該函數時,就可以省略第2個參數,效果是刪除從第1個參數所指位置(包括該位置)起的所有字符(正如下邊示例中有關str3的操作和輸出)。原因是len=npos,而npos一定大於string對象的最大長度。
示例:
#include<iostream>
#include<string>
using namespace std;
int main()
{
string str1("123456789");
string str2("123456789");
string str3("123456789");
string str4("123456789");
string str5("123456789");
string str6("123456789");
string str7("123456789");
string str8("123456789");
str1.erase(2, 3);
cout << str1 << endl;//126789
str2.erase(2, 10); cout << endl;//空行
str3.erase(7);//注意這裡的參數值不能超過str3.length(),否則會出現運行時錯誤等於是輸出空行,相當於刪除'\0'及其後面的(當然後面什麼也沒有,
//因為'\0'已經是最後一個)
cout << str3 << endl;//1234567 當省略第2個參數時,刪除第1個參數所指位置起(即包括該位置)的所有字符
//str4.erase(10, 5);//這麼做不行
//cout << str4 << endl;
str4.erase(str4.begin());
cout << str4 << endl;//23456789
str5.erase(str5.begin() + 2);
cout << str5<< endl;//12456789
//str6.erase(str6.begin() + 10);//這麼做不行
//cout << str6 << endl;
str6.erase(str6.end() - 2);
cout << str6 << endl;//12345679
//str7.erase(str7.end() - 10);//這麼做不行
//cout << str7 << endl;
str7.erase(str7.begin()+2,str7.end()-2);
str7.erase(str7.begin() + 2, str7.end() - 2);
cout << str7 << endl;//1289 刪除從str7.begin()+2(包括str7.begin()+2)到str7.end() - 2(包括str7.end() - 2)的所有字符
//str8.erase(str8.begin() + 7, str8.end() - 5);//這麼做不行
//cout << str8 << endl;
return 0;
}
4.clear()
原型:
void clear() noexcept;
作用:
刪除字符串的所有內容。
示例:
#include<iostream>
#include<string>
using namespace std;
int main()
{
string str("123456789");
str.clear();
cout << str << endl;//空行
cout << str.length() << endl;//0
return 0;
}
5.insert()
原型:
//string (1)
basic_string& insert (size_type pos, const basic_string& str);
//substring (2)
basic_string& insert (size_type pos, const basic_string& str,
size_type subpos, size_type sublen);
//c-string (3)
basic_string& insert (size_type pos, const charT* s);
//buffer (4)
basic_string& insert (size_type pos, const charT* s, size_type n);
//fill (5)
basic_string& insert (size_type pos, size_type n, charT c);
iterator insert (const_iterator p, size_type n, charT c);
//single character (6)
iterator insert (const_iterator p, charT c);
//range (7)
template <class InputIterator>
iterator insert (iterator p, InputIterator first, InputIterator last);
//initializer list (8)
basic_string& insert (const_iterator p, initializer_list<charT> il);
說明:
1)原型(8)與list容器有關,是C++11新標准,這裡贊不詳述。
2)以上原型中出現的返回值和參數有iterator和InputIterator與迭代器有關,這裡也暫不詳述,可以將其簡單地理解為指針,begin()和end()的返回值與它們匹配。
示例:
#include<iostream>
#include<string>
using namespace std;
int main()
{
/*
*測試basic_string& insert (size_type pos, const basic_string& str);
*/
string st1("123456789");
//string st2("123456789");
string str1("abc");
st1.insert(3, str1);
cout << st1 << endl;//123abc456789 注意是在pos所指位置前插入
//st2.insert(10, str1);//超出范圍
//cout << st2 << endl;//不可以
/*
**測試basic_string& insert (size_type pos, const basic_string& str,size_type subpos, size_type sublen);
*/
string st2("123456789");
string st3("123456789");
string str2("abcdefg");
st2.insert(3, str2, 2, 3);
cout << st2 << endl;//123cde456789
st3.insert(3, str2, 4, 9);//超出范圍
cout << st3 << endl;//123efg456789 可見如果超出字符串的長度,則一直到字符串的最後,不補空格
/*
**測試basic_string& insert (size_type pos, const charT* s);
*/
string st4("123456789");
string st5("123456789");
char* str3 = "abc";
st4.insert(3, str3);
cout << st4 << endl;//123abc456789
st5.insert(3, "abc");
cout << st5 << endl;//123abc456789
/*
**測試basic_string& insert (size_type pos, const charT* s, size_type n);
*/
string st6("123456789");
string st7("123456789");
st6.insert(3, "abcdefg", 3);//n可以為0,為0時什麼也不加 當n為負值時會出現運行時錯誤
cout << st6 << endl;//123abc456789
st7.insert(3, "abcdefg", 20);//超出范圍
cout << st7 << endl;//123abcdefg i n v a l i 456789 調大n值(如500)進行測試,發現中間多出來的是報錯的語句和亂碼,且每次運行的輸出可能不一樣
//CodeBlocks12.11上中間直接就是亂碼
/*
**測試basic_string& insert (size_type pos, size_type n, charT c); 和 iterator insert (const_iterator p, size_type n, charT c);
*/
string st8("123456789");
string st9("123456789");
st8.insert(3, 2, 'a');
cout << st8 << endl;//123aa456789
st9.insert(st9.begin() + 3, 2, 'a');
cout << st9 << endl;//123aa456789
/*
**測試iterator insert (const_iterator p, charT c);
*/
string ss1("123456789");
ss1.insert(ss1.begin()+3, 'a');//由原型知,這裡不能將ss1.begin()+3改為3
cout << ss1 << endl;//123a456789
/*
**測試template <class InputIterator>
** iterator insert (iterator p, InputIterator first, InputIterator last);
*/
string ss2("123456789");
string str4("abcdefg");
ss2.insert(ss2.begin() + 3, str4.begin(), str4.begin()+3);//超出范圍會出現運行時錯誤
cout << ss2 << endl;//123abc456789
return 0;
}
6.append()
原型:
//string (1)
basic_string& append (const basic_string& str);
//substring (2)
basic_string& append (const basic_string& str, size_type subpos, size_type sublen);
//c-string (3)
basic_string& append (const charT* s);
//buffer (4)
basic_string& append (const charT* s, size_type n);
//fill (5)
basic_string& append (size_type n, charT c);
//range (6)
template <class InputIterator>
basic_string& append (InputIterator first, InputIterator last);
//initializer list(7)
basic_string& append (initializer_list<charT> il);
(7)不詳述。
示例:
#include<iostream>
#include<string>
using namespace std;
int main()
{
/*
**測試basic_string& append (const basic_string& str);
*/
string st1("123456789");
string str1("abc");
string& ss = st1.append(str1);
cout << ss << endl;//123456789abc
cout << st1 << endl;//123456789abc
/*
**測試basic_string& append (const basic_string& str, size_type subpos, size_type sublen);
*/
string st2("123456789");
string st3("123456789");
string str2("abcdefg");
st2.append(str2, 2, 3);
cout << st2 << endl;//123456789cde
st3.append(str2, 3, 20);//超出范圍
cout << st3 << endl;//123456789defg 當用數字表示范圍時,若超出范圍,則直到字符串的結尾,不會補空格,也不會出現運行時錯誤
cout << st3.length() << endl;//13 盡管如此,在實際編程時,也必須保證不超范圍
/*
**測試basic_string& append (const charT* s);
*/
string st4("123456789");
st4.append("abc");
cout << st4 << endl;//123456789abc
/*
**測試basic_string& append (const charT* s, size_type n);
*/
string st5("123456789");
st5.append("abc", 5);//超出范圍
cout << st5 << endl;//123456789abc+亂碼
/*
**測試basic_string& append (size_type n, charT c);
*/
string st6("123456789");
st6.append(3, 0x41);//可以用16進制的ASCII碼
cout << st6 << endl;//123456789AAA
/*
**測試template <class InputIterator>
**basic_string& append (InputIterator first, InputIterator last);
*/
/*
string st7("123456789");
string str3("abcdefg");
st6.append(str3.begin() + 2, str3.begin() + 10);//超出范圍
cout << st7 << endl;//當使用迭代器時,若超出范圍,則會出現運行時錯誤
*/
return 0;
}
7.replace()
原型:
//string (1)
basic_string& replace (size_type pos, size_type len, const basic_string& str);
basic_string& replace (const_iterator i1, const_iterator i2, const basic_string& str);
//substring (2)
basic_string& replace (size_type pos, size_type len, const basic_string& str,
size_type subpos, size_type sublen);
//c-string (3)
basic_string& replace (size_type pos, size_type len, const charT* s);
basic_string& replace (const_iterator i1, const_iterator i2, const charT* s);
//buffer (4)
basic_string& replace (size_type pos, size_type len, const charT* s, size_type n);
basic_string& replace (const_iterator i1, const_iterator i2, const charT* s, size_type n);
//fill (5)
basic_string& replace (size_type pos, size_type len, size_type n, charT c);
basic_string& replace (const_iterator i1, const_iterator i2, size_type n, charT c);
//range (6)
template <class InputIterator>
basic_string& replace (const_iterator i1, const_iterator i2,
InputIterator first, InputIterator last);
//initializer list (7)
basic_string& replace (const_iterator i1, const_iterator i2, initializer_list<charT> il);
(7)不詳述
示例:(這裡僅給出部分原型的測試,其它的讀者可參照前面幾個函數的實例自行測試)
#include<iostream>
#include<string>
using namespace std;
int main()
{
/*
**測試basic_string& replace (size_type pos, size_type len, const basic_string& str);
*/
string st1("123456789");
string str1("abcde");
string str2("ab");
st1.replace(2, 3, str1);//將位置2開始的3個字符(345)換成abcde
cout << st1 << endl;//12abcde6789
string st2("123456789");
st2.replace(1, 7, str1);
cout << st2 << endl;//1abcde9
string st3("123456789");
st3.replace(6, 9, str2);//超出范圍
cout << st3 << endl;//123456ab
/*
**測試basic_string& replace (const_iterator i1, const_iterator i2, const basic_string& str);
*/
/*string st4("123456789");
st4.replace(st4.begin() + 8, st4.begin() + 10, str1); //迭代器超范圍,出現運行時錯誤
cout << st4 << endl;*/
/*
**測試basic_string& replace (size_type pos, size_type len, const charT* s, size_type n);
*/
string st5("123456789");
st5.replace(2, 3, "abcdefg", 5);
cout << st5 << endl;//12abcde6789
string st6("123456789");
st6.replace(2, 3, "abc", 20);//超出范圍
cout << st6 << endl;//12abc+亂碼+6789 對於char*類型,若超出范圍,就會出現亂碼
return 0;
}
以上各函數的原型及參數的意義大同小異,讀者可以觸類旁通。現結合以上各示例,對“超出范圍”這一特殊情況給出一般性的規律總結:
1.對於string類型,用數字表示范圍,超出時,自動截止到字符串的末尾,不會補空格,不會有亂碼,也不會出現運行時錯誤。
2.對於string類型,用迭代器表示范圍,超出時,出現運行時錯誤。
3.對於char*類型,用數字表示范圍(只能用數字表示,char*是基本類型,沒有迭代器),超出時,會出現亂碼。
------------------------------分割線------------------------------
C++ Primer Plus 第6版 中文版 清晰有書簽PDF+源代碼 http://www.linuxidc.com/Linux/2014-05/101227.htm
讀C++ Primer 之構造函數陷阱 http://www.linuxidc.com/Linux/2011-08/40176.htm
讀C++ Primer 之智能指針 http://www.linuxidc.com/Linux/2011-08/40177.htm
讀C++ Primer 之句柄類 http://www.linuxidc.com/Linux/2011-08/40175.htm
將C語言梳理一下,分布在以下10個章節中: