目录
温馨提示:这篇文章有约两万字
什么是string类?
一. 定义和初始化string对象
1.string的构造函数的形式:
2.拷贝赋值运算符
3.assign函数
二.string对象上的操作
1.读写string对象
2.读取未知数量的string对象
3.使用getline 读取一整行
4.string对象的大小和容量:
编辑
4.1string::size_type类型
5.string的字符串比较
5.1用关系运算符
5.2用compare函数
编辑
6.string的加法
6.1两个string对象相加
6.2字面值和string对象相加
7 元素访问
7.1下标访问
7.2at函数
8.substr操作
9.insert函数
10.append 和replace函数
11.string的搜索操作
12 string的遍历:借助迭代器 或者 下标法
13. string的删除:erase()
14、 string的字符替换:
15. string的大小写转换:
16、 string的查找:find
17、 string的排序:sort(s.begin(),s.end())
18、 string的分割/截取字符串:strtok() & substr()
数值的转换
string 和数值之间的转换
温馨提示:这篇文章有约两万字
什么是string类?
在C++中,string
是一个用于处理字符串的类,它属于C++标准库中的一部分。
string
类提供了一种方便且安全的方式来处理字符序列,相比于C语言中的字符数组(即C-style strings)或字符指针,C++的string
类提供了更多的功能和更好的安全性。
作为标准库的一部分,string定义在命名空间std中。接下来的示例都假定已包含了下述代码:
#include <string>
using std::string;
一. 定义和初始化string对象
string对象可通过构造函数和拷贝赋值运算符来初始化string对象
我们可以先看看string的构造函数是如何初始化string对象的
1.string的构造函数的形式:
string str;//生成空字符串string s(str);//字符串s为str的副本string s(str, strbegin,strlen);
//将字符串str中从下标strbegin开始、长度为strlen的部分作为字符串初值string s(cstr, char_len);
//以C_string类型cstr的前char_len个字符串作为字符串s的初值string s(num ,c);
//生成num个c字符的字符串string s(str, stridx);
//将字符串str中从下标stridx开始到字符串结束的位置作为字符串初值
我们看个例子
#include <iostream>
#include <string>
using namespace std;void test1()
{string str1; //生成空字符串string str2("123456789"); //生成"1234456789"的复制品string str3("12345", 0, 3);//结果为"123"string str4("0123456", 5); //结果为"01234"string str5(5, '1'); //结果为"11111"string str6(str2, 2); //结果为"3456789"cout<<"str2:"<<str2<<endl;cout<<"str3:"<<str3<<endl;cout<<"str4:"<<str4<<endl;cout<<"str5:"<<str5<<endl;cout<<"str6:"<<str6<<endl;
}int main()
{test1();return 0;
}
2.拷贝赋值运算符
string s1;
string s2=s1;//s2是s1的副本
string s3="hello";//s3是字面值"helo"的副本,除了那个空字符之外
3.assign函数
在C++的std::string类中,assign()函数用于给字符串赋值。这个函数有多种重载形式,可以接受不同类型的参数,以便从其他字符串、字符数组、单个字符或子字符串来分配内容。
以下是assign()函数的一些常见用法:
从另一个std::string对象赋值:
std::string str1 = "Hello"; std::string str2; str2.assign(str1); // str2 现在包含 "Hello"
从C风格的字符串(字符数组)赋值:
const char* cstr = "World"; std::string str; str.assign(cstr); // str 现在包含 "World"
从单个字符赋值,并指定重复次数:
char ch = 'a'; std::string str; str.assign(5, ch); // str 现在包含 "aaaaa"
从另一个std::string的子字符串赋值:
std::string str = "Hello, World!"; std::string subStr; subStr.assign(str, 7, 5); // 从索引7开始,长度为5的子字符串,subStr 现在包含 "World"
注意,在上面的例子中,子字符串的索引是从0开始的,并且长度参数指定了要复制的字符数(不包括结束的空字符)。
从迭代器范围赋值:
如果你的数据来自标准库容器(如std::vector或std::list),你可以使用迭代器来指定要复制的范围。但是,由于std::string本身不是基于迭代器的容器,这种用法并不常见。但如果你有一个字符类型的容器,并且想将其内容转换为std::string,这种方法可能会有用。
std::vector<char> vec = {'H', 'e', 'l', 'l', 'o'}; std::string str; str.assign(vec.begin(), vec.end()); // str 现在包含 "Hello"
从初始化列表赋值(C++11及更高版本):
std::string str; str.assign({'a', 'b', 'c'}); // str 现在包含 "abc" // 或者直接使用初始化列表构造函数 std::string anotherStr = {'d', 'e', 'f'}; // anotherStr 现在包含 "def"
使用assign()函数可以灵活地给字符串分配新的内容,同时替换掉字符串中原有的内容。如果assign()函数接收的参数会导致新字符串的长度超过当前字符串的容量,那么std::string可能会重新分配内存以存储新的内容。
二.string对象上的操作
一个类除了要规定初始化其对象的方式外,还要定义对象上所能执行的操作。
其中,类既能定义通过函数名调用的操作,下面列举了string的大多数操作。
os<<s
//从is中读取字符串赋给s,字符串以空白分隔,返回isis>>s
//从is中读取一行赋给s,返回isgetline(is,s)
//从is中读取一行赋值给s,返回iss.empty()
//s为空返回true,否则返回falses.size()
//返回s中字符的个数s[n]
//返回s中第n个字符的引用,位置n从0计起s1+s2
//返回s1和s2连接后的结果sl=s2
//用s2的副本代替s1中原来的字符s1==s2
s1!=s2
//如果s1和s2中所含的字符完全一样,则它们相等;string对象的相等性判断对字母的大小写敏感<,<=,>,
//利用字符在字典中的顺序进行比较,且对字母的大小写敏感
1.读写string对象
我们可以使用标准库中的iostream来读写int、double等内置类型的值。同样,也可以使用IO操作符读写string对象:
注意:要想编译下面的代码还需要适当的#include 语句和using声明
int main()
{
string s;//空字符串cin >>s;//将string对象读入s,遇到空白停止cout << s << endl;//输出s
return 0;
}
这段程序首先定义一个名为s的空string,然后将标准输入的内容读取到s中。在执行读取操作时,string对象会自动忽略开头的空白(即空格符、换行符、制表符等)并从第一个真正的字符开始读起,直到遇见下一处空白为止。
如上所述,如果程序的输入是
Hello World!
则输出将是
Hello
输出结果中没有任何空格。
和内置类型的输入输出操作一样,string对象的此类操作也是返回运算符左侧的运算对象作为其结果。因此,多个输入或者多个输出可以连写在一起:
string s1, s2;
cin >>s1 >> s2;// 把第一个输入读到 s1中,第二个输入读到 s2中
cout << sl << s2 << endl;
//输出两个string对象
假设给上面这段程序输入与之前一样的内容
Hello World!
输出将是
HelloWorld!
2.读取未知数量的string对象
下面编写一个类似的程序用了读取string对象:
#include<iostream
#include<string>
int main()
{
string word;
//反复读取,直至到达文件末尾
while (cin >> word)
{
//逐个输出单词,每个单词后面紧跟一个换行
cout << word << endl;
}
return 0;
}
在该程序中,读取的对象是string。
该条件负责在读取时检测流的情况,如果流有效,也就是说没遇到文件结束标记或非法输入,那么执行while语句内部的操作。
此时,循环体将输出刚刚从标准输入读取的内容。重复若干次之后,一旦遇到文件结束标记或非法输入循环也就结束了。
3.使用getline 读取一整行
有时我们希望能在最终得到的字符串中保留输入时的空白符,这时应该用getline函数代替原来的>>运算符。
getline函数的参数是一个输入流和一个string对象,函数从给定的输入流中读入内容,直到遇到换行符为止(注意换行符也被读进来了),然后把所读的内容存入到那个string对象中去(注意不存换行符)。
getline只要一遇到换行符就结束读取操作并返回结果,哪怕输入的一开始就是换行符也是如此。如果输入真的一开始就是换行符,那么所得的结果是个空string。
和输入运算符一样,getline 也会返回它的流参数。因此既然输入运算符能作为判断的条件,我们也能用getline的结果作为条件。
例如,可以通过改写之前的程序让它一次输出一整行,而不再是每行输出一个词了:
int main()
{
string line;
//每次读入一整行,直至到达文件末尾
while (getline(cin, line))
cout << line << endl;
return 0;
}
因为line中不包含换行符,所以我们手动地加上换行操作符。和往常一样,使用endl结束当前行并刷新显示缓冲区。
触发getline函数返回的那个换行符实际上被丢弃掉了,得到的string对象中并不包含该换行符。
4.string对象的大小和容量:
- size()和length():返回string对象的字符个数,他们执行效果相同。
- max_size():返回string对象最多包含的字符数,超出会抛出length_error异常
- capacity():重新分配内存之前,string对象能包含的最大字符数
void test2()
{string s("1234567");cout << "size=" << s.size() << endl;cout << "length=" << s.length() << endl;cout << "max_size=" << s.max_size() << endl;cout << "capacity=" << s.capacity() << endl;}
4.1string::size_type类型
对于size函数来说,返回一个int或者返回一个 unsigned 似乎都是合情合理的。
但其实 size 函数返回的是一个string::size_type类型的值,下面就对这种新的类型稍作解释。
string类及其他大多数标准库类型都定义了几种配套的类型。这些配套类型体现了标准库类型与机器无关的特性,类型size_type 即是其中的一种。在具体使用的时候,通过作用域操作符来表明名字size_type 是在类string中定义的。
尽管我们不太清楚string::size_type 类型的细节,但有一点是肯定的:它是个无符号类型的值而且能足够存放下任何string对象的大小。所有用于存放 string 类的size 函数返回值的变量,都应该是string::size_type类型的。
过去,string::size_type 这种类型有点儿神秘,不太容易理解和使用。在C++11新标准中,允许编译器通过auto或者decltype来推断变量的类型:
auto len = line.size();// len的类型是string::size_type
由于size函数返回的是一个无符号整型数,因此切记,如果在表达式中混用了带符号数和无符号数将可能产生意想不到的结果。
例如,假设n是一个具有负值的int,则表达式s.size()<n的判断结果几乎肯定是true。这是因为负值n会自动地转换成一个比较大的无符号值。
如果一条表达式中已经有了size()函数就不要再使用int了,这样可以避免混用int和unsigned可能带来的问题。
5.string的字符串比较
5.1用关系运算符
string类定义了几种用于比较字符串的运算符。这些比较运算符逐一比较string对象中的字符,并且对大小写敏感,也就是说,在比较时同一个字母的大写形式和小写形相等性运算符(==和!=)分别检验两个string对象相等或不相等,string对象相等意味着它们的长度相同而且所包含的字符也全都相同。
关系运算符<、<=、>、>=分别检验一个string对象是否小于、小于等于、大于、大于等于另外一个string对象。上述这些运算符都依照(大小写敏感的)字典顺序:
- 如果两个string 对象的长度不同,而且较短string对象的每个字符都与较长string 对象对应位置上的字符相同,就说较短string 对象小于较长string对象。
- 如果两个string 对象在某些对应的位置上不一致,则string对象比较的结果其实是string对象中第一对相异字符比较的结果。
下面是string 对象比较的一个示例:
string str ="Hello";
string phrase = "Hello World"
string slang = "Hiya";
根据规则1可判断,对象str小于对象phrase;根据规则2可判断,对象slang 既大于str也大于phrase。
5.2用compare函数
另一个功能强大的比较函数是成员函数compare()。他支持多参数处理,支持用索引值和长度定位子串来进行比较。
他返回一个整数来表示比较结果,返回值意义如下:0:相等 1:大于 -1:小于 (A的ASCII码是65,a的ASCII码是97)
void test3()
{// (A的ASCII码是65,a的ASCII码是97) // 前面减去后面的ASCII码,>0返回正值,<0返回负值,相同返回0 std::string A("aBcd");std::string B("Abcd");std::string C("123456");std::string D("123dfg");// "aBcd" 和 "Abcd"比较------ a < A std::cout << "A.compare(B):" << A.compare(B) << std::endl;// "cd" 和 "Abcd"中的"bc"比较------- c > b std::cout << "A.compare(2, 2, B, 1, 2):" << A.compare(2, 2, B, 1, 2) << std::endl;// "cd" 和 "Abcd"中的"cd"比较------- 相等 std::cout << "A.compare(2, 2, B, 2, 2):" << A.compare(2, 2, B, 2, 2) << std::endl;// "123" 和 "123dfg"中的"123"比较------- 相等 std::cout << "C.compare(0, 3, D, 0, 3):" << C.compare(0, 3, D, 0, 3) << std::endl;
}
6.string的加法
6.1两个string对象相加
两个string 对象相加得到一个新的string对象,其内容是把左侧的运算对象与右侧的运算对象串接而成。
也就是说,对string 对象使用加法运算符(+)的结果是一个新的string对象,它所包含的字符由两部分组成:前半部分是加号左侧string对象所含的字符、后半部分是加号右侧string对象所含的字符。
另外,复合赋值运算符(+=)】负责把右侧string 对象的内容追加到左侧string对象的后面:
string sl="hello,",s2 = "world\n";//s3的内容是hello,world\n
string s3 = sl + s2;s1+=s2;
// 等价于s1=s1+s2
6.2字面值和string对象相加
即使一种类型并非所需,我们也可以使用它,不过前提是该种类型可以自动转换成所需的类型。
因为标准库允许把字符字面值和字符串字面值转换成string对象,所以在需要string对象的地方就可以使用这两种字面值来替代。
利用这一点将之前的程序改写为如下形式:
string sl = "hello",s2= "world";//在s1和s2中都没有标点符号
string s3=s1+","+s2+'\n';
当把string对象和字符字面值及字符串字面值混在一条语句中使用时,必须确保每个加法运算符(+)的两侧的运算对象至少有一个是string:
string s4=s1+",";
//正确:把一个string对象和一个字面值相加string s5 ="hello"+",";
// 错误:两个运算对象都不是string//正确:每个加法运算符都有一个运算对象是string
string s6= s1 +","+ "world";string s7="hello"+","+s2;//错误:不能把字面值直接相加
s4和s5初始化时只用到了一个加法运算符,因此很容易判断是否合法。
s6的初始化形式之前没有出现过,但其实它的工作机理和连续输入连续输出是一样的,可以用如下的形式分组:
string s6 = (sl + ",")+ "world";
其中子表达式s1+“,”的结果是一个string 对象,它同时作为第二个加法运算符的左侧运算对象,因此上述语句和下面的两个语句是等价的:
string tmp = s1 +",”;//正确:加法运算符有一个运算对象是strings6 = tmp + "world";
// 正确:加法运算符有一个运算对象是string
另一方面,s7的初始化是非法的,根据其语义加上括号后就成了下面的形式:
string s7=("hello"+",")+ s2;//错误:不能把字面值直接相加
很容易看到,括号内的子表达式试图把两个字符串字面值加在一起,而编译器根本没法做到这一点,所以这条语句是错误的。
因为某些历史原因,也为了与C兼容,所以C++语言中的字符串字面值并不是标准库类型string的对象。切记,字符串字面值与string是不同的类型。
7 元素访问
7.1下标访问
在C++中,std::string 类型的对象提供了类似数组的下标访问(也称为索引访问)来直接访问字符串中的字符。你可以使用下标操作符 [] 或者 at() 函数来访问字符串中指定位置的字符。
使用下标操作符 [] 进行随机访问非常简单,但需要注意的是,如果你访问了字符串范围之外的索引,程序不会报错(即不会进行范围检查),这可能会导致未定义行为(如访问无效内存)。
下面是一个使用下标操作符 [] 访问 std::string 中字符的示例:
#include <iostream> #include <string> int main() { std::string str = "Hello, World!"; // 访问字符串中的第一个字符 char firstChar = str[0]; // 访问索引为0的字符,即'H' std::cout << "First character: " << firstChar << std::endl; // 访问字符串中的随机位置的字符(确保索引在范围内) size_t randomIndex = 7; // 假设我们随机选择了索引7 if (randomIndex < str.size()) { char randomChar = str[randomIndex]; // 访问索引为7的字符,即'W' std::cout << "Random character at index " << randomIndex << ": " << randomChar << std::endl; } else { std::cout << "Index out of range!" << std::endl; } return 0; }
7.2at函数
在C++的std::string类中,at()函数是一个成员函数,它提供了对字符串中字符的带范围检查的访问。当你使用at()函数访问字符串中的字符时,如果提供的索引超出了字符串的有效范围(即小于0或大于等于字符串的长度),那么at()函数会抛出一个std::out_of_range异常。
这是使用at()函数的一个基本示例:
#include <iostream> #include <string> #include <stdexcept> int main() { std::string str = "Hello, World!"; // 使用at()访问索引为0的字符 char firstChar = str.at(0); std::cout << "First character: " << firstChar << std::endl; // 尝试访问索引为字符串长度(或更大)的字符,这将抛出异常 try { char invalidChar = str.at(str.length()); // 注意:索引是从0开始的,所以str.length()是无效的索引 std::cout << "Invalid character: " << invalidChar << std::endl; } catch (const std::out_of_range& e) { std::cout << "Caught an out_of_range exception: " << e.what() << std::endl; } // 尝试访问一个负数索引,这也将抛出异常 try { char invalidChar = str.at(-1); std::cout << "Invalid character: " << invalidChar << std::endl; } catch (const std::out_of_range& e) { std::cout << "Caught an out_of_range exception: " << e.what() << std::endl; } return 0; }
在这个示例中,我们尝试使用at()函数访问字符串str中索引为str.length()和-1的字符。由于这两个索引都是无效的(一个在字符串末尾之后,一个在字符串开始之前),因此at()函数会抛出std::out_of_range异常。我们使用try-catch块来捕获这些异常并输出一条错误消息。
请注意,与下标操作符[]不同,at()函数总是进行范围检查,因此使用at()函数可以提供更安全的字符串访问方式。然而,由于范围检查的开销,使用at()函数可能会比使用下标操作符[]稍微慢一些(尽管在现代处理器和编译器优化下,这种差异通常可以忽略不计)。
8.substr操作
substr操作返回一个string,它是原始string的一部分或者全部的拷贝。可以传递给substr一个可选的开始位置和计数值
s.substr(pos,n)string s("hello world");string s2 = s.substr(0,5);// s2 = hellostring s3 = s.substr(6);// s3 = worldstring s4 = s.substr(6, 11);// s3 = worldstring s5 =s.substr(12);//抛出一个out_of_range异常
如果开始位置超过了string的大小,则substr函数抛出一个out_of_range异常。如果开始位置加上计数值大于string的大小,则substr会调整计数值,只拷贝到string的末尾。
表9.12:子字符串操作
返回一个string,包含s中从pos开始的n个字符的拷贝。pos的默认值为0。n的默认值为s.size()-pos,即拷贝从pos开始的所有字符
9.insert函数
在C++的std::string类中,insert()函数用于在字符串的指定位置插入一个或多个字符。这个函数有多种重载形式,可以接受不同类型的参数,以便从其他字符串、字符数组、单个字符或子字符串来插入内容。
以下是insert()函数的一些常见用法:
在指定位置插入一个字符:
std::string str = "Hello"; str.insert(1, 'i'); // 在索引1的位置插入'i',str现在包含"Hiello"
在指定位置插入一个字符串:
std::string str = "Hello"; std::string ins = "World"; str.insert(5, ins); // 在索引5的位置插入"World",str现在包含"HelloWorld"
在指定位置插入指定次数的字符:
std::string str = "Hello"; str.insert(5, 3, '!'); // 在索引5的位置插入3个'!',str现在包含"Hello!!!"
在指定位置插入另一个字符串的子串:
std::string str = "Hello"; std::string ins = "World, World!"; str.insert(5, ins, 7, 5); // 在索引5的位置插入ins从索引7开始的5个字符,即"World",str现在包含"HelloWorld"
注意,在上面的例子中,子字符串的索引是从0开始的,并且长度参数指定了要插入的字符数(不包括结束的空字符)。
使用迭代器插入字符序列:
如果你的数据来自标准库容器(如std::vector或std::list),并且你想在std::string中插入这些容器的元素,你可以使用迭代器来指定要插入的范围。但是,由于std::string存储的是字符,所以迭代器应该是指向字符的迭代器。
std::vector<char> vec = {'i', 'n', 's', 'e', 'r', 't'}; std::string str = "Hello"; str.insert(str.begin() + 1, vec.begin(), vec.end()); // 在索引1的位置插入vec的所有元素,str现在包含"Hinsertello"
使用insert()函数可以灵活地在字符串的任意位置插入新的内容。如果insert()函数接收的参数会导致新字符串的长度超过当前字符串的容量,那么std::string可能会重新分配内存以存储新的内容。
用于c风格字符串
std::string str = "Hello"; const char* cstr = "World"; // C风格字符串 // 在str的末尾插入cstr str.insert(str.length(), cstr); // 现在str包含"HelloWorld" // 在str的指定位置插入cstr的子串 str.insert(5, cstr + 1, 3); // 从cstr的第1个字符开始插入3个字符,即"orl",现在str包含"HelloWorldorl"
10.append 和replace函数
string类定义了两个额外的成员函数:append和replace,这两个函数可以改变string的内容。
ppend 操作是在string末尾进行插入操作的一种简写形式:
string s("C++ Primer"), s2= s: // 将s和s2初始化为"Ct+ Primer"s.insert(s.size(),"4th Ed.");// s =="C++ Primer 4th Ed."s2.append(" 4th Ed.");
//等价方法:将"4th Ed."追加到s2;S ==s2
replace 操作是调用erase和insert的一种简写形式:
//将"4th“替换为"5th"的等价方法
s.erase(11, 3);// s =="C++ Primer Ed."
s.insert(11, "5th");// s == "C++ Primer 5th Ed."//从位置11开始,删除3个字符并插入"5th"
s2.replace(11,3,"5th"); //等价方法:s==s2
此例中调用replace时,插入的文本恰好与删除的文本一样长。这不是必须的,可以插入一个更长或更短的string:
s.replace(11, 3, "Fifth");
// s == "C++ Primer Fifth Ed."
在此调用中,删除了3个字符,但在其位置插入了5个新字符。
11.string的搜索操作
在C++的std::string类中,有多种搜索操作可以用来查找子字符串或字符在字符串中的位置。以下是一些常用的搜索函数:
find():
这个函数用于在字符串中查找子字符串或字符首次出现的位置。如果找到,它返回子字符串或字符首次出现的位置的索引;如果未找到,则返回std::string::npos。
std::string str = "Hello, World!"; size_t pos = str.find("World"); // pos现在是7 pos = str.find(','); // pos现在是5 pos = str.find('o'); // pos现在是4(找到第一个'o') pos = str.find("NotPresent"); // pos现在是std::string::npos
rfind():
这个函数与find()类似,但它是从字符串的末尾开始搜索,返回子字符串或字符最后一次出现的位置的索引。
std::string str = "banana"; size_t pos = str.rfind('a'); // pos现在是5(找到最后一个'a')
find_first_of():
这个函数在字符串中查找参数中任何一个字符首次出现的位置。
std::string str = "Hello, World!"; size_t pos = str.find_first_of("ld"); // pos现在是2(找到'l') pos = str.find_first_of("XYZ"); // pos现在是std::string::npos(没找到)
find_first_not_of():
这个函数在字符串中查找第一个不属于参数中任何字符的字符的位置。
std::string str = "Hello, 123 World!"; size_t pos = str.find_first_not_of("0123456789"); // pos现在是7(找到',') pos = str.find_first_not_of("abcdefghijklmnopqrstuvwxyz"); // pos现在是7(找到',')
find_last_of():
这个函数在字符串中查找参数中任何一个字符最后一次出现的位置。
std::string str = "banana"; size_t pos = str.find_last_of("an"); // pos现在是5(找到最后一个'a')
find_last_not_of():
这个函数在字符串中查找最后一个不属于参数中任何字符的字符的位置。
std::string str = "Hello, 123 World!"; size_t pos = str.find_last_not_of("0123456789"); // pos现在是12(找到' ')
这些函数都接受一个可选的起始位置参数,允许你从字符串的某个特定位置开始搜索。例如:
std::string str = "Hello, World!"; size_t pos = str.find("o", 5); // 从索引5开始查找'o',pos现在是7(找到第二个'o')
请注意,所有的位置索引都是从0开始的,而std::string::npos是一个特殊的常量,表示“未找到”。
12 string的遍历:借助迭代器 或者 下标法
void test6()
{string s1("abcdef"); // 调用一次构造函数// 方法一: 下标法for( int i = 0; i < s1.size() ; i++ ){cout<<s1[i];}cout<<endl;// 方法二:正向迭代器string::iterator iter = s1.begin();for( ; iter < s1.end() ; iter++){cout<<*iter;}cout<<endl;// 方法三:反向迭代器string::reverse_iterator riter = s1.rbegin();for( ; riter < s1.rend() ; riter++){cout<<*riter;}cout<<endl;
}
13. string的删除:erase()
1. iterator erase(iterator p);//删除字符串中p所指的字符2. iterator erase(iterator first, iterator last);//删除字符串中迭代器区间[first,last)上所有字符3. string& erase(size_t pos = 0, size_t len = npos);//删除字符串中从索引位置pos开始的len个字符4. void clear();//删除字符串中所有字符
void test6()
{string s1 = "123456789";// s1.erase(s1.begin()+1); // 结果:13456789// s1.erase(s1.begin()+1,s1.end()-2); // 结果:189s1.erase(1,6); // 结果:189string::iterator iter = s1.begin();while( iter != s1.end() ){cout<<*iter;*iter++;}cout<<endl;}
14、 string的字符替换:
1. string& replace(size_t pos, size_t n, const char *s);//将当前字符串从pos索引开始的n个字符,替换成字符串s2. string& replace(size_t pos, size_t n, size_t n1, char c); //将当前字符串从pos索引开始的n个字符,替换成n1个字符c3. string& replace(iterator i1, iterator i2, const char* s);//将当前字符串[i1,i2)区间中的字符串替换为字符串s
void test7()
{string s1("hello,world!");cout<<s1.size()<<endl; // 结果:12s1.replace(s1.size()-1,1,1,'.'); // 结果:hello,world.// 这里的6表示下标 5表示长度s1.replace(6,5,"girl"); // 结果:hello,girl.// s1.begin(),s1.begin()+5 是左闭右开区间s1.replace(s1.begin(),s1.begin()+5,"boy"); // 结果:boy,girl.cout<<s1<<endl;
}
15. string的大小写转换:
tolower()和toupper()函数 或者 STL中的transform算法
方法一:使用C语言之前的方法,使用函数,进行转换
#include <iostream>
#include <string>
using namespace std;int main()
{string s = "ABCDEFG";for( int i = 0; i < s.size(); i++ ){s[i] = tolower(s[i]);}cout<<s<<endl;return 0;
}
方法二:通过STL的transform算法配合的toupper和tolower来实现该功能
#include <iostream>
#include <algorithm>
#include <string>using namespace std;int main()
{string s = "ABCDEFG";string result;transform(s.begin(),s.end(),s.begin(),::tolower);cout<<s<<endl;return 0;
}
16、 string的查找:find
1. size_t find (constchar* s, size_t pos = 0) const;//在当前字符串的pos索引位置开始,查找子串s,返回找到的位置索引,-1表示查找不到子串2. size_t find (charc, size_t pos = 0) const;//在当前字符串的pos索引位置开始,查找字符c,返回找到的位置索引,-1表示查找不到字符3. size_t rfind (constchar* s, size_t pos = npos) const;//在当前字符串的pos索引位置开始,反向查找子串s,返回找到的位置索引,-1表示查找不到子串4. size_t rfind (charc, size_t pos = npos) const;//在当前字符串的pos索引位置开始,反向查找字符c,返回找到的位置索引,-1表示查找不到字符5. size_tfind_first_of (const char* s, size_t pos = 0) const;//在当前字符串的pos索引位置开始,查找子串s的字符,返回找到的位置索引,-1表示查找不到字符6. size_tfind_first_not_of (const char* s, size_t pos = 0) const;//在当前字符串的pos索引位置开始,查找第一个不位于子串s的字符,返回找到的位置索引,-1表示查找不到字符7. size_t find_last_of(const char* s, size_t pos = npos) const;//在当前字符串的pos索引位置开始,查找最后一个位于子串s的字符,返回找到的位置索引,-1表示查找不到字符8. size_tfind_last_not_of (const char* s, size_t pos = npos) const;//在当前字符串的pos索引位置开始,查找最后一个不位于子串s的字符,返回找到的位置索引,-1表示查找不到子串1
void test8()
{string s("dog bird chicken bird cat");//字符串查找-----找到后返回首字母在字符串中的下标// 1. 查找一个字符串cout << s.find("chicken") << endl; // 结果是:9// 2. 从下标为6开始找字符'i',返回找到的第一个i的下标cout << s.find('i',6) << endl; // 结果是:11// 3. 从字符串的末尾开始查找字符串,返回的还是首字母在字符串中的下标cout << s.rfind("chicken") << endl; // 结果是:9// 4. 从字符串的末尾开始查找字符cout << s.rfind('i') << endl; // 结果是:18-------因为是从末尾开始查找,所以返回第一次找到的字符// 5. 在该字符串中查找第一个属于字符串s的字符cout << s.find_first_of("13br98") << endl; // 结果是:4---b// 6. 在该字符串中查找第一个不属于字符串s的字符------先匹配dog,然后bird匹配不到,所以打印4cout << s.find_first_not_of("hello dog 2006") << endl; // 结果是:4cout << s.find_first_not_of("dog bird 2006") << endl; // 结果是:9// 7. 在该字符串最后中查找第一个属于字符串s的字符cout << s.find_last_of("13r98") << endl; // 结果是:19// 8. 在该字符串最后中查找第一个不属于字符串s的字符------先匹配t--a---c,然后空格匹配不到,所以打印21cout << s.find_last_not_of("teac") << endl; // 结果是:21}
17、 string的排序:sort(s.begin(),s.end())
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;void test9()
{string s = "cdefba";sort(s.begin(),s.end());cout<<"s:"<<s<<endl; // 结果:abcdef
}
18、 string的分割/截取字符串:strtok() & substr()
strtok():分割字符串
void test10()
{char str[] = "I,am,a,student; hello world!";const char *split = ",; !";char *p2 = strtok(str,split);while( p2 != NULL ){cout<<p2<<endl;p2 = strtok(NULL,split);}
}
void test11()
{string s1("0123456789");string s2 = s1.substr(2,5); // 结果:23456-----参数5表示:截取的字符串的长度cout<<s2<<endl;
}
数值的转换
字符串中常常包含表示数值的字符。
例如,我们用两个字符的string 表示数值15-字符'1'后跟字符'5'。
一般情况,一个数的字符表示不同于其数值。数值15如果保存为16位的short 类型,则其二进制位模式为0000000000001111,而字符串"15”存为两个Latin-1 编码的char,二进制位模式为0011000100110101。第一个字节表示字符'1,其八进制值为:061,第二个字节表示151,其Latin-1编码为八进制值065。
新标准引入了多个函数,可以实现数值数据与标准库string之间的转换:
int i =42
string s = to_ string(i);;// 将整数i转换为字符表示形式
double d = stod(s);//将字符串 s转换为浮点数
此例中我们调用to_string 将42转换为其对应的string表示,然后调用stod将此string转换为浮点值。
要转换为数值的string中第一个非空白符必须是数值中可能出现的字符:
string s2 = "pi = 3.14";//转换s中以数字开始的第一个子串,结果d=3.14
d= stod(s2.substr(s2.find_first _of("+-.0123456789")));
在这个stoa调用中,我们调用了find first_of来获得s中第一个可能是数值的一部分的字符的位置。我们将s中从此位置开始的子串传递给stodestod函数读取此参数,处理其中的字符,直至遇到不可能是数值的一部分的字符,然后它就将找到的这个数值的字符串表示形式转换为对应的双精度浮点值。
string 参数中第一个非空白符必须是符号(+或-)或数字。
它可以以0x或0x开头来表示干六进制数。对那些将字符串转换为浮点值的函数,string参数也可以以小数点(.)开头,并可以包含e或E来表示指数部分。
对于那些将字符串转换为整型值的函数,根据基数不同,string参数可以包含字母字符,对应大于数字9的数。
如果string不能转换为一个数值,这些函数抛出一个invalid_argument异常。如果转换得到的数值无法用任何类型来表示,则抛出一个out_of_range异常。
string 和数值之间的转换
to_string(val);
//一组重载函数,返回数值val的string 表示。val可以是任何算术类型。
//对每个浮点类型和int或更大的整型,都有相应版本的to_string。
//与往常一样,小整型会被提升stoi(s,p,b); //返回s的起始子串(表示整数内容)的数值,
stol(s,p,b); //返回值类型分别是int、long, unsigned long,
stoul(s,p,b); // long long unsigned long long.
stoll(s,p,b); //b表示转换所用的基数,默认值为10。
stoull(s,p,b);stof(s,p,b); //p是size_t指针,用来保存s中第一个非数值字符的下标,P默认为0,
stod(s,p,b); //即,函数不保存下标返回s的起始子串(表示浮点数内容)的数值,
stold(s,p,b); //返回值类型分别是float、double或long double。参数p的作用与整数转换函数中一样
举个例子
std::stol
(string to long):将字符串转换为长整数。
long num = std::stol("123456789012345");
std::stof
(string to float):将字符串转换为浮点数。
float num = std::stof("123.45");
使用 std::to_string
:将整数、浮点数或长整数转换为字符串。
#include <string> int main() { int num = 123; std::string str = std::to_string(num); // str现在是"123" double dnum = 123.45; std::string dstr = std::to_string(dnum); // dstr现在是"123.45"(可能包含更多小数位) return 0;
}