string(字符串)
在程序设计过程中,字符串使用非常频繁,在C语言里面,所有字符串处理均是基于字符数组,包括一系列字符串处理函数,均是作用与字符数组之上。但在使用数据的过程中,会出现很多问题,比如字符数组越界,内存分配,包括一些函数作用于数组之上都比较麻烦,因此在C++里面提供了专门处理字符串的类string。在使用string时,我们完全可以将其视为一个基本的数据类型。同时,前面容器对里面提到,string是序列容器,连续存储,有很多优点,在实际开发过程中能够提供很大的便利。
头文件:#include
构造函数
std::string s0 ("Initial string");
// constructors used in the same order as described above:
std::string s1;
std::string s2 (s0);
std::string s3 (s0, 8, 3);
std::string s4 ("A character sequence", 6);
std::string s5 ("Another character sequence");
std::string s6 (10, 'x');
std::string s7a (10, 42);
std::string s7b (s0.begin(), s0.begin()+7);
std::cout << "s1: " << s1 << "\ns2: " << s2 << "\ns3: " << s3;
std::cout << "\ns4: " << s4 << "\ns5: " << s5 << "\ns6: " << s6;
std::cout << "\ns7a: " << s7a << "\ns7b: " << s7b << '\n';
//Output
/*
s1:
s2: Initial string
s3: str
s4: A char
s5: Another character sequence
s6: xxxxxxxxxx
s7a: **********
s7b: Initial
*/
迭代器
- string是字符串类,类似于字符数组,但它同时也是容器,可以看成是存储字符的容器。因此,它也有迭代器。
string s1("hello world.");
string::iterator it;
string::reverse_iterator rit;
it = s1.begin();
it = s1.end();
rit = s1.rbegin();
rit = s2.rend();
for (it = s1.begin(); it != s1.end(); it++)
{
cout << *it;
}
string容量(大小、长度等)
string s1("hello world");
cout << s1.length() << endl; //返回字符串长度
cout << s1.size() << endl; //返回字符串大小,与size函数完全相同,只是为了兼容容器
cout << s1.max_size() << endl; //返回字符串最大大小,(一般不使用)
s1.clear(); //清空字符串
cout << s1.capacity() << endl; //返回字符串所占空间大小,不一定等于size()函数返回值
s1.shrink_to_fit(); //C++11里面很多容器都添加了这个函数,主要是为了压缩容器所占空间,压缩为合适的大小(有预留空间的容器都有这个函数)
元素访问
string s1("hello world");
cout << s1[i] << endl; //直接利用下标、索引访问第i个元素
cout << s1.at(i) <<endl; //调用at函数访问。[与利用下标访问相比,多了越界检查]
cout << s1.back() << endl; //(C++11)访问最后一个元素
cout << s1.front() << endl; //(c++11)访问第一个元素
修改元素
string s1("hello world");
string s2("I'm ok");
//添加元素
s1 += "ok.."; //直接利用操作符进行添加,可以是字符串或者字符
s1 += s2;
s1 += '\n'
s1.append(s2); //利用append函数在末尾添加字符串,不能是字符
s1.append(s2, 4, 2); //将s2中起始下标为4,长度为2的字符串添加到s1
s1.append(s2, 2); //将s2中起始下标为0,长度为2的字符串添加到s1
s1.append(s2.begin(), s2.end());
s1.push_back('c'); //向s1添加字符,添加字符只能是利用"+="或者push_back函数
//插入元素
s1.insert(pos, s2); //在s1的pos位置前面插入s2 (这里pos的取值范围是[0, s1.size()],共有size+1个插入位置)
s1.insert(6, "ok");
s1.insert(6, s2, 4, 2); //在s1[6]前面插入s2从s2[4]开始的两个元素
s1.insert(s1.begin(), 'c'); //在s1前面插入字符'c'
s1.insert(s1.begin(), s2.begin(), s2.end()); //利用迭代器插入字符串
//删除元素
s1.erase(pos, 3); //删除s1[pos]开始的3个元素
s1.erase(s1.begin() + 1); //删除s1[1]的元素
s1.erase(s1.begin(), s1.begin()+2); //删除s1[0]与s1[2]之间的元素,从s1[0]开始,不包括s1[2]
//元素替换
s1[0] = 'z'; //直接利用下标索引进行修改
s1.replace(9, 5, "OK");
s1.replace(9, 5, s2); //把从s1[9]开始的5个元素替换为s2
s1.replace(9, 5, s2, 0, 3);
s1.replace(9, 5, 3, '!');
s1.replace(s1.begin(), s1.begin+5, s2);
s1.swap(s2); //s1与s2进行互换
s1.pop_bac(); //删除最后元素
很多函数参数都有一个“套路”,第pos个元素开始(下标从0开始),接下来的参数是长度为L。也即截取这一段进行操作。
字符串操作
string s1("hello world");
string s2("I'm ok");
s1.c_str(); //返回s1的头指针,也即字符数组指针,string是连续存储,相当于字符数组,但返回的是一个const char * 类型指针,所以不能修改里面的值
s1.data(); //返回s1的头指针,与c_str()函数返回相同值
int pos = -1;
//字符串查找
pos = s1.find("world") //返回world第一次出现的位置索引
pos = s1.find('w'); //查找字符
pos = s1.find("world", pos+1, 5); //从s1中pos+1位置开始查找字符串"world",并且查找字字符串长度为5
pos = s1.rfind("world"); //返回world最后一次出现的位置索引
//string::npos 为空位置,如果未查找到,则返回值为string::npos
//字符查找
pos = s1.find_first_of("abcd"); //查找"abcd"字符串中任一个字符在s1中最先出现的位置
pos = s1.find_first_of('a', pos+1); //从s1中pos+1位置开始查找a第一次出现的位置
std::string str ("PLease, replace the vowels in this sentence by asterisks.");
std::string::size_type found = str.find_first_of("aeiou");
while (found!=std::string::npos)
{
str[found]='*';
found=str.find_first_of("aeiou",found+1);
}
std::cout << str << '\n';
s1.find_last_of(s2); //寻找s2中每一个字符最后在s1中出现的位置
s1.find_first_not_of(s2); //在s1中寻找第一个没有在s2中出现的字符的位置
s1.find_last_not_of(s2);
//字符串截取
substr函数原型
basic_string substr (size_type pos = 0, size_type len = npos) const;
s2 = s1.substr(pos, len); //在s1中截取从pos开始,长度为len的子字符串
s2 = s1.substr(); //默认截取整个字符串
s2 = s2.substr(pos); //截取从pos到结束的子字符串(函数默认参数只能从右往左定义,省略的参数只能是左边的)
//字符串比较
int com;
com = s1.compare("asdf");
com = s1.compare(s2);
com = s1.compare(2, 3, s2); //从s1中截取以s1[2]开始,长度为3的子字符串,与s2进行比较
/*返回值说明
=0:两个比较的字符串完全相同
>0:当出现第一个不相同的字符位置p,s1[p] > s2[p],或者s2的长度小于s1
<0:当出现第一个不相同的字符位置p,s1[p] < s2[p],或者s1的长度小于s2
一般返回值是0, 1, -1
*/
//Output
/*
Pl**s*, r*pl*c* th* v*w*ls *n th*s s*nt*nc* by *st*r*sks.
*/
其它非成员函数
string s1("hello");
string s2("world");
string s3;
s3 = s1 + s2;
getline(in, s3); //从输入流in里面读取一行数据到s3,输入流可以是标准输入流cin,或者文件输入流ifstream
//整数与字符串相互转换
string s4("120.55");
int na = 177;
int nb = 0;
float fb = 0.0;
double db = 0.0;
nb = stoi(s4);
nb = stol(s4);
nb = stoul(s4);
nb = stoll(s4);
nb = stoull(s4);
fb = stof(s4);
db = stof(s4);
//除了以上转换函数之外,还有一些string与int相互转换的方法(sscanf与sprintf)
int i;
sscanf("17", "%d", &i); //i = 17
sscanf("17", "%x", &i) //i = 23
sscanf("OX17", "%x", &i); //i = 23
sscanf(s4.c_str(), "%f", &fb); //i = 120.55
int a = 30;
char c[20];
int len = sprintf(c, "%d", a);
//利用stringsstream
后记
- string是C++开发中用的最多的类,虽然在各个开发平台(如MFC、BCB)都封装了自己的字符串类,但使用string进行开发,尤其是跨平台会更为方便。string操作方便,可以直接进行字符串连接,利用下标取值,插入、删除、查找等,结合这些函数可以完成其它一些更为复杂的操作。如字符串分割,下面是一段字符串分割的程序。
#include <iostream>
#include <string>
#include <vector>
using namespace std;
//利用string的find编写字符串分割函数
vector<string> split(string target, string pattern)
{
vector<string> result;
target += pattern;
string::size_type found = target.find_first_of(pattern);
int pos = 0;
while (found != string::npos)
{
string tmp = target.substr(pos, found - pos);
if (tmp.size() != 0)
{
result.push_back(tmp);
}
pos = found + 1;
found = target.find_first_of(pattern, found+1);
}
return result;
}
int main()
{
string s1 = "hello world, my name is cypress.";
vector<string> res = split(s1, " ,.");
for each (string s in res)
{
cout << s << " ";
}
return 0;
}
//Output
/*
hello world my name is cypress
*/