C++string类使用大全

 

目录

温馨提示:这篇文章有约两万字

什么是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,字符串以空白分隔,返回is

is>>s
//从is中读取一行赋给s,返回is

getline(is,s)
//从is中读取一行赋值给s,返回is

s.empty()
//s为空返回true,否则返回false

s.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对象的大小和容量:

  1. size()和length():返回string对象的字符个数,他们执行效果相同。
  2. max_size():返回string对象最多包含的字符数,超出会抛出length_error异常
  3. 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对象。上述这些运算符都依照(大小写敏感的)字典顺序:

  1. 如果两个string 对象的长度不同,而且较短string对象的每个字符都与较长string 对象对应位置上的字符相同,就说较短string 对象小于较长string对象。
  2. 如果两个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 +",”;//正确:加法运算符有一个运算对象是string

s6 = 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 = hello

string s3 = s.substr(6);// s3 = world

string s4 = s.substr(6, 11);// s3 = world

string 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);   // 结果:189
    s1.erase(1,6);                       // 结果:189
    string::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个字符,替换成字符串s

2. string& replace(size_t pos, size_t n, size_t n1, char c); //将当前字符串从pos索引开始的n个字符,替换成n1个字符c

3. string& replace(iterator i1, iterator i2, const char* s);//将当前字符串[i1,i2)区间中的字符串替换为字符串s
void test7()
{
    string s1("hello,world!");

    cout<<s1.size()<<endl;                     // 结果:12
    s1.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匹配不到,所以打印4
    cout << s.find_first_not_of("hello dog 2006") << endl; // 结果是:4
    cout << 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,然后空格匹配不到,所以打印21
    cout << 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;  
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/588527.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

软件工程毕业设计选题100例

文章目录 0 简介1 如何选题2 最新软件工程毕设选题3 最后 0 简介 学长搜集分享最新的软件工程业专业毕设选题&#xff0c;难度适中&#xff0c;适合作为毕业设计&#xff0c;大家参考。 学长整理的题目标准&#xff1a; 相对容易工作量达标题目新颖 1 如何选题 最近非常多的…

Mac brew安装Redis之后更新配置文件的方法

安装命令 brew install redis 查看安装位置命令 brew list redis #查看redis安装的位置 % brew list redis /usr/local/Cellar/redis/6.2.5/.bottle/etc/ (2 files) /usr/local/Cellar/redis/6.2.5/bin/redis-benchmark /usr/local/Cellar/redis/6.2.5/bin/redis-check-ao…

高级商务谈判口才培训教程(3篇)

高级商务谈判口才培训教程&#xff08;3篇&#xff09; 高级商务谈判口才培训教程&#xff08;**篇&#xff09;&#xff1a;基础篇 一、前言 在高级商务谈判中&#xff0c;口才不仅是交流的工具&#xff0c;更是策略执行的关键。本教程将从基础出发&#xff0c;带领大家逐步掌…

【PHP】安装指定版本Composer

1、下载指定版本composer.phar文件&#xff1a;https://github.com/composer/composer/releases 2、将下载的文件添加到全局路径&#xff1a; sudo mv composer.phar /usr/local/bin/composer 3、赋予权限&#xff1a; sudo chmod x /usr/local/bin/composer 4、查看compos…

52.HarmonyOS鸿蒙系统 App(ArkTS)配置文件添加多个权限方法

52.HarmonyOS鸿蒙系统 App(ArkTS)配置文件添加多个权限方法 module.json5

前端开发者如何在项目里控制修改组件的样式

1为了让自己快速下班&#xff0c;修改样式应该是占据大部分时间&#xff0c;在很多组件库的项目里&#xff0c;都会提到主题设置。 比如element的scss配置变量&#xff0c;通常有人喜欢直接引入css样式来快速完成任务&#xff0c;然后在全局覆盖这些选择器对应的样式&#xff0…

OpenCV(二)—— 车牌定位

从本篇文章开始我们进入 OpenCV 的 Demo 实战。首先&#xff0c;我们会用接下来的三篇文章介绍车牌识别 Demo。 1、概述 识别图片中的车牌号码需要经过三步&#xff1a; 车牌定位&#xff1a;从整张图片中识别出牌照&#xff0c;主要操作包括对原图进行预处理、把车牌从整图…

信号知识详解

目录 1、信号的产生 2、core 核心转储 3、信号的保存 4、信号的处理 信号是linux系统提供的&#xff0c;让用户或进程给其他进程发送异步信息的一种方式。 常见的信号处理方式&#xff1a; 1、默认行为 2、忽略 3、自定义 1、信号的产生 1、kill命令 我们可以使用命令 k…

过渡与动画

单元素/组件过渡 Vue在插入、更新或者移除 DOM 时&#xff0c;提供多种不同方式的过渡效果&#xff08;一个淡入淡出的效果&#xff09; 在条件渲染&#xff08;使用v-if&#xff09;、条件展示&#xff08;使用v-show&#xff09;、动态组件、组件根节点等情形中&#xff0c;可…

【火猫DOTA2】电竞世界杯DOTA2项目将在7月份的前三周举办

1、电竞世界杯将于今年7月3日至8月25日在沙特利雅得举办。近日主办方公布了各个项目的举办时间,其中DOTA2项目将在7月份的前三周举办。转载:火猫TV资讯https://www.huomaotv.com/ 目前Falcons、XG、GG和Liquid这五支赢得了足够EPT积分的队伍已经确定直邀沙特。剩下的三个名额还…

SpringBoot集成Kafka开发

4.SpringBoot集成Kafka开发 4.1 创建项目 4.2 配置文件 application.yml spring:application:name: spring-boot-01-kafka-basekafka:bootstrap-servers: 192.168.2.118:90924.3 创建生产者 package com.zzc.producer;import jakarta.annotation.Resource; import org.spri…

MATLAB 数据输出

MATLAB 数据输出 数据导出(或输出)在 MATLAB 的意思是写入文件。MATLAB 允许您在另一个读取 ASCII 文件的应用程序中使用您的数据。为此&#xff0c;MATLAB 提供了几个数据导出选项。 您可以创建以下类型的文件- 数组中的矩形、分隔的ASCII数据文件。 击键的日记&#xff08…

Linux系统安装Redis7(详细版)

Linux系统安装Redis7 一、windows安装redis二、Linux安装Redis下载redis编辑redis7.conf文件启动redis-server服务如何关闭redis服务设置Redis开机自启动 一、windows安装redis Window 下安装 下载地址&#xff1a;https://github.com/dmajkic/redis/downloads 下载到的Redi…

6.k8s中的secrets资源

一、Secret secrets资源&#xff0c;类似于configmap资源&#xff0c;只是secrets资源是用来传递重要的信息的&#xff1b; secret资源就是将value的值使用base64编译后传输&#xff0c;当pod引用secret后&#xff0c;k8s会自动将其base64的编码&#xff0c;反编译回正常的字符…

OpenCV(一) —— OpenCV 基础

1、OpenCV 简介 OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是一个基于 BSD 许可开源发行的跨平台的计算机视觉库。可用于开发实时的图像处理、计算机视觉以及模式识别程序。由英特尔公司发起并参与开发&#xff0c;以 BSD 许可证授权发行&#xff0c…

【QT学习】14.线程学习

一。线程了解 线程是计算机科学中的一个重要概念&#xff0c;它是操作系统能够进行运算调度的最小单位。线程是进程中的一个执行流&#xff0c;一个进程可以包含多个线程。与进程相比&#xff0c;线程更轻量级&#xff0c;可以更高效地利用计算机资源。 线程有以下几个特点&…

vue3+ts 原生 js drag drop 实现

vue3ts 原生 js drag drop 实现 一直以来没有涉及的一个领域就是 drag drop 拖动操作&#xff0c;研究了下&#xff0c;实现了&#xff0c;所以写个教程。 官方说明页面及实例&#xff1a;https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API 最终效果&…

企业计算机服务器中了lockbit勒索病毒如何处理,lockbit勒索病毒解密流程建议

在虚拟的网络世界里&#xff0c;人们利用网络获取信息的方式有很多&#xff0c;网络为众多企业提供了极大便利性&#xff0c;也大大提高了企业生产运营效率&#xff0c;方便企业开展各项工作业务。但随着网络技术的不断发展与应用&#xff0c;越来越多的企业开始关注企业网络数…

Flutter笔记:Widgets Easier组件库(8)使用图片

Flutter笔记 Widgets Easier组件库&#xff08;8&#xff09;&#xff1a;使用图片 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress o…

使用递归函数,将一串数字每位数相加求和

代码结果&#xff1a; #include<stdio.h> int DigitSum(unsigned int n) {if (n > 9)return DigitSum(n / 10) (n % 10);elsereturn n; } int main() {unsigned int n;scanf("%u", &n);int sum DigitSum(n);printf("%d\n", sum);return 0; …