标准库的String类型详解
String 是C++标准库STL里面的一种常用的容器,(相当于保存数据类型为char的vector容器)。这个类提供了相当丰富的函数来进行对自身元素字符串的操作,以及与C风格字符串之间的转换。
在C语言里,处理字符串是一件相当困难的事。(因为通常在使用字符串操作的时候会用到一个相当不容易驾驭的类型:指针)
比如下面这个例子:
123456789101112131415 | //example char 12 ] = "Hello" ; char *p 'h' ; //改变第一个字母 //example char "Hello" ; *ptr 'h' ; //错误 |
第一个字符串数组是变量,是一个可变值得存储空间。而第二个字符串却是一个广义上的常量,指针只是指向存储常量的那块存储空间。
String 被设计出来主要是为了支持长度可变的字符串,以及一些常用的抽象操作方便用户进行多种字符串操作,满足对字符串的一半应用。
使用 String 对象的时候必须包含头文件和命名空间的指定:
123 | # include <string> using |
一. string对象的初始化
string标准库支持几个构造函数用于初始化对象:
123456789 | string // 生成一个空字符串s string // 拷贝构造函数 生成str的复制品 string // 将字符串str内“始于位置stridx”的部分当作字符串的初值 string // 将字符串str内“始于stridx且长度顶多strlen”的部分作为字符串的初值 string // 将C字符串作为s的初值 string // 将C字符串前chars_len个字符作为字符串s的初值。 string // 生成一个字符串,包含num个c字符 string // 以区间beg;end(不包含end)内的字符作为字符串s的初值 s.~string() // 销毁所有字符,释放内存 |
特别的,因为不能直接把string对象复制给C风格的字符串:
12 | string var = "Olympic" ; const char *p = var .c_str(); //Correct! |
为了和C语言兼容,C++的string对象提供了一个c_str()方法,但是为了防止意外的修改string对象,注意其返回值为 const char * ;
12 | string var = "Olympic" ; const char *p = var .c_str(); //Correct! |
二. string对象的读写操作
string的读写方式为:
1. 忽略前导所有的非法字符(空格,换行符,制表符)。
2. 直到碰到第一个非法字符为止 。
利用 getline() 读取整行字符串 :
1 | getline(cin, // 第一个参数为一个输入流对象,第二个参数为一个string对象; |
( getline() 操作不吸收最后面的换行符,但是会吸收前面的换行符,所以当前面吸收换行符之后,line会被置为string )
三. string对象的函数操作
1. C++字符串和C字符串的转换:
C++ 提供的字符串转化为C所对应的C_string的方法有 data(); c_str(); copy();
其中data(); 以字符数组的形式返回字符串内容,但是并不添加'\0' 。
c_str(); 则返回一个以'\0'结尾的字符数组 。
而copy()则把字符串的内容复制或写入既有的c_string或字符数组内。
因为 C++字符串并不以’\0’结尾。
2. string的大小和容量:
一个C++字符串存在3种大小:
现有字符数: size(); length(); empty();
当前C++最大能包含字符数: max_size();
为string重新分配内存: reserve();
3. 元素存取:
两种方法:一种是用下标操作符[]进行索引取值,一种是利用 .at();函数进行取值;
需要注意的 [] 操作符并不检查索引值是否有效,而 at() 函数会检查索引的有效性,如过非法,则会抛出out_of_range错误。
123456789101112131415 | Str[ 3 ]; // ok Str.at( 3 ); // ok Str[ 100 ]; // 未定义的行为 Str.at( 100 ); // throw out_of_range Str[Str.length()] // 未定义行为 Cstr[Cstr.length()] // 返回 ‘\0’ Str.at(Str.length()); // throw out_of_range Cstr.at(Cstr.length()) // throw out_of_range Str[ 100 ]; // 未定义的行为 Str.at( 100 ); // throw out_of_range Str[Str.length()] // 未定义行为 Cstr[Cstr.length()] // 返回 ‘\0’ Str.at(Str.length()); // throw out_of_range Cstr.at(Cstr.length()) // throw out_of_range |
4. 比较函数:
C++字符串支持常见的比较操作符(>,>=,<,<=,==,!=),甚至支持string与C-string的比较(如 str<”hello”)。在使用>,>=,<,<=这些操作符的时候是根据“当前字符特性”将字符按字典顺序进行逐一得比较。字典排序靠前的字符小,比较的顺序是从前向后比较,遇到不相等的字符就按这个位置上的两个字符的比较结果确定两个字符串的大小。同时,string(“aaaa”) 另一个功能强大的比较函数是成员函数compare()。他支持多参数处理,支持用索引值和长度定位子串来进行比较。他返回一个整数来表示比较结果,返回值意义如下:(0 - 相等) (>0 - 大于) (<0 - 小于) 。
1234567 | string s.compare(“abcd”); // 返回0 s.compare(“dcba”); // 返回一个小于0的值 s.compare(“ab”); // 返回大于0的值 s.compare(s); // 相等 s.compare( 0 , 2 , s, 2 , 2 ); // 用”ab”和”cd”进行比较 小于零 s.compare( 1 , 2 , ”bcx”, 2 ); // 用”bc”和”bc”比较。 |
123456 | int compare ( const string& str ) const ; int compare ( const char* s ) const ; int compare ( size_t pos1, size_t n1, const string& str ) const ; int compare ( size_t pos1, size_t n1, const char* s) const ; int compare ( size_t pos1, size_t n1, const string& str, size_t pos2, size_t n2 ) const ; int compare ( size_t pos1, size_t n1, const char* s, size_t n2) const ; |
5. 修改内容:
赋值:
第一个赋值方法当然是使用操作符=,新值可以是string(如:s=ns) 、c_string(如:s=”gaint”)甚至单一字符(如:s=’j’)。还可以使用成员函数assign(),这个成员函数可以使你更灵活的对字符串赋值。
123456 | s.assign(str); // 不说 s.assign(str, 1 , 3 ); // 如果str是”iamangel” 就是把”ama”赋给字符串 s.assign(str, 2 , string::npos); // 把字符串str从索引值2开始到结尾赋给s s.assign(“gaint”); // 不说 s.assign(“nico”, 5 ); // 把’n’ ‘I’ ‘c’ ‘o’ ‘\0’赋给字符串 s.assign( 5 , ’x’); // 把五个x赋给字符串s |
清空:
把字符串的方法有三个:s=””; s.clear(); s.erase();
增加字符:
(这里说的增加是在尾巴上),函数有 +=、 append()、 push_back() 。
123456789 | s // 加个字符串 s is jiayp”; // 加个C字符串 s // 加个字符 s.append(str); s.append(str, 1 , 3 ); // 不解释了 同前面的函数参数assign的解释 s.append(str, 2 , string::npos) // 不解释了 s.append(“my is jiayp”); s.append(“nico”, 5 ); s.append( 5 , ’x’); |
字符串操作:
字符串操作是一个不小的主题,在标准C++中,string字符串类成为一个标准,之所以抛弃char*的字符串而选用C++标准程序库中的string类,是因为他和前者比较起来,不必担心内存是否足够、字符串长度等等,而且作为一个类出现,他集成的操作函数足以完成我们大多数情况下的需要.
下面我们首先从一些示例开始学习下string类的使用:
1)
123456789 | # include <string> # include <iostream> using namespace std;
void main() { string s( "hehe" ); cout << s << endl;
cin. get ();
} |
2)
12345678910 | # include <string> # include <iostream> using namespace std;
void main() { char chs[] = "hehe" ; string s(chs); cout << s << endl;
cin. get ();
} |
3)
12345678910 | # include <string> # include <iostream> using namespace std;
void main() { char chs[] = "hehe" ; string s(chs, 1 , 3 ); // 指定从chs的索引1开始,最后复制3个字节 cout << s << endl;
cin. get ();
} |
4)
12345678910 | # include <string> # include <iostream> using namespace std;
void main() { string s1( "hehe" ); string s2(s1); cout << s2 << endl;
cin. get ();
} |
5)
12345678910 | # include <string> # include <iostream> using namespace std; void main() { string s1( "hehe" , 2 , 3 ); string s2(s1); cout << s2 << endl; cin. get (); } |
6)
1234567891011 | # include <string> # include <iostream> using namespace std; void main() { char chs[] = "hehe" ; string s(chs, 3 ); // 将chs前3个字符作为初值构造 cout << s << endl; cin. get (); } |
7)
1234567891011 | # include <string> # include <iostream> using namespace std; void main() { string s( 10 , 'k' ); // 分配10个字符,初值都是'k' cout << s << endl; cin. get (); } // |
8)
1234567891011121314151617 | // # include <string> # include <iostream> using namespace std; void main() { string s( 10 , 'k' ); // 分配10个字符,初值都是'k' cout << s << endl; s = "hehehehe" ; cout << s << endl; s.assign( "kdje" ); cout << s << endl; s.assign( "fkdhfkdfd" , 5 ); // 重新分配指定字符串的前5的元素内容 cout << s << endl; cin. get (); } |
9)
123456789101112131415 | # include <string> # include <iostream> using namespace std; void main() { string s1 = "hehe" ; string s2 = "gagaga" ; cout << "s1 : " << s1 << endl; cout << "s2 : " << s2 << endl; s1.swap(s2); cout << "s1 : " << s1 << endl; cout << "s2 : " << s2 << endl; cin. get (); } |
10)
12345678910111213141516 | //+=,append(),push_back()在尾部添加字符 # include <string> # include <iostream> using namespace std; void main() { string s = "hehe" ; s += "gaga" ; cout << s << endl; s.append( "嘿嘿" ); // append()方法可以添加字符串 cout << s << endl; s.push_back( 'k' ); // push_back()方法只能添加一个字符... cout << s << endl; cin. get (); } |
11)
1234567891011121314 | // # include <string> # include <iostream> using namespace std; void main() { string s = "hehe" ; s.insert( 0 , "头部" ); // 在头部插入 s.insert(s.size(), "尾部" ); // 在尾部插入 s.insert(s.size() / 2 , "中间" ); // 在中间插入 cout << s << endl; cin. get (); } |
12)
1234567891011121314 | # include <string> # include <iostream> using namespace std; void main() { string s = "abcdefg" ; s.erase( 0 , 1 ); // 从索引0到索引1,即删除掉了'a' cout << s << endl; // s.replace( 2 , 3 , "" ); // 即将指定范围内的字符替换成"",即变相删除了 cout << s << endl; cin. get (); } |
13)
12345678910111213141516171819 | //clear() # include <string> # include <iostream> using namespace std; void main() { string s = "abcdefg" ; cout << s.length() << endl; s.clear(); cout << s.length() << endl; // s = "dkjfd" ; cout << s.length() << endl; s.erase( 0 , s.length()); cout << s.length() << endl; cin. get (); } |
14)
123456789101112 | //replace() # include <string> # include <iostream> using namespace std; void main() { string s = "abcdefg" ; s.replace( 2 , 3 , "!!!!!" ); // 从索引2开始3个字节的字符全替换成"!!!!!" cout << s << endl; cin. get (); } |
15)
1234567891011121314151617181920212223 | // # include <string> # include <iostream> using namespace std; void main() { string s1 = "abcdefg" ; string s2 = "abcdefg" ; if (s1 == s2)cout << "s1 == s2" << endl; else cout << "s1 != s2" << endl; if (s1 != s2)cout << "s1 != s2" << endl; else cout << "s1 == s2" << endl; if (s1 > s2)cout << "s1 > s2" << endl; else cout << "s1 <= s2" << endl; if (s1 <= s2)cout << "s1 <= s2" << endl; else cout << "s1 > s2" << endl; cin. get (); } |
16)
12345678910111213 | // # include <string> # include <iostream> using namespace std; void main() { string s = "abcdefg" ; cout << s.size() << endl; cout << s.length() << endl; cin. get (); } |
17)
123456789101112 | // # include <string> # include <iostream> using namespace std; void main() { string s = "abcdefg" ; cout << s.max_size() << endl; cin. get (); } |
18)
123456789101112131415161718192021 | // # include <string> # include <iostream> using namespace std; void main() { string s ; if (s.empty()) cout << "s 为空." << endl; else cout << "s 不为空." << endl; s = s + "abcdefg" ; if (s.empty()) cout << "s 为空." << endl; else cout << "s 不为空." << endl; cin. get (); } |
19)
12345678910111213141516171819202122232425 | // # include <string> # include <iostream> using namespace std; void main() { string s = "abcdefg1111" ; cout << "use []:" << endl; for ( int i = 0 ; i < s.length(); i++) { cout << s[i] << endl; } cout << endl; cout << "use at():" << endl; for ( int i = 0 ; i < s.length(); i++) { cout << s.at(i) << endl; } cout << endl; cin. get (); } |
20)
123456789101112131415161718192021222324 | # include <string> # include <iostream> using namespace std; void main() { string s = "abcdefg1111" ; const char * chs1 = s.c_str(); const char * chs2 = s.data(); cout << "use at():" << endl; int i; for (i = 0 ; i < s.length(); i++) { cout << "c_str() : " << chs1[i] << endl; cout << "data() : " << chs2[i] << endl; } cout << "c_str() : " << chs1 << endl; cout << "data() : " << chs2 << endl; cout << endl; cin. get (); } |
21)
1234567891011121314 | // # include <string> # include <iostream> using namespace std; void main() { string s = "abcdefg1111" ; string str = s.substr( 5 , 3 ); // 从索引5开始3个字节 cout << str << endl; cin. get (); } |
22)
12345678910111213141516 | // # include <string> # include <iostream> using namespace std; void main() { string s = "abcdefg1111" ; string pattern = "fg" ; string::size_type pos; pos = s.find(pattern, 0 ); // 从索引0开始,查找符合字符串"f"的头索引 cout << pos << endl; string str = s.substr(pos, pattern.size()); cout << str << endl; cin. get (); } |
23)
12345678910111213141516 | // # include <string> # include <iostream> using namespace std; void main() { string s = "abcdefg1111" ; for (string::iterator iter = s.begin(); iter != s.end(); iter++) { cout << *iter << endl; } cout << endl; cin. get (); }
|