C++:STL - string

news2024/11/20 3:30:14

C++:STL - string

    • basic_string
    • string
      • string的常见构造
      • string的输入输出
        • operator<<
        • c_str
        • operator>>
        • getline
      • string访问及遍历
        • operator[ ] & at
        • font & back
        • 迭代器
          • begin & end
          • rbegin & rend
        • 范围for
      • string的容量操作
        • size & length
        • max_size
        • capacity
        • clear
        • empty
        • reserve
        • resize
        • shrink_to_fit
      • string的修改操作
        • push_back
        • append
        • operator+=
        • insert
        • erase
        • replace
        • swap
      • string的查找操作
        • find
        • refind
        • sub_str
        • find_first_of & find_first_not_of
        • find_last_of & find_last_not_of


C语言中,字符串是以'\0'结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合面向对象的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。

所以在C++的STL库中提供了更加方便的string类。


basic_string

basic_string是C++中的一个标准库类,用于表示字符串。它是在标准库命名空间std中定义的。basic_string是一个模板类,根据需要可以用不同的字符类型来实例化,比如charwchar_t等。

basic_string下,有四个特化版本:

在这里插入图片描述

在世界上,计算机的字符有非常多的编码形式,比如UTF-8UTF-16UTF-32等等。每种字符编码形式,都有对应的解码规则,所以C++的>STL库提供了几种基本的类,而我们最常用的UTF-8万国码,就适用于string类。所以本博客讲解的也是string

基本上,string类提供了basic_string类的所有功能,并且提供了一些额外的操作,使得字符串的处理更加方便。因此,大多数情况下,我们会使用string类来处理字符串。


string

string的常见构造

在这里插入图片描述

string类提供了多个构造函数,用于创建字符串对象。下面详细讲解一下每个构造函数的用法和示例:

  1. 默认构造函数:string()
    • 创建一个空字符串对象。
    • 示例:
    string str;
    

  1. 拷贝构造函数:string(const string& str)
    • 创建一个字符串对象,内容为另一个字符串对象str的拷贝。
    • 示例:
     string str1("hello");
     string str2(str1); // "hello"
    

  1. 重载构造函数:string(const string& str, size_t pos, size_t len = npos)
    • 创建一个字符串对象,内容为字符串对象str的pos位置开始的len个字符。
    • 示例:
     string str1("hello"); 
     string str2(str1, 1, 3); // "ell:
    
    • 注意:当不传入第三个参数时,其默认为npos,这个值是size_t的最大储存值,可以理解为是无穷大,也就是说,当不传入第三个参数,其会从pos位置开始拷贝到结束。

  1. 重载构造函数:string(const char* s)
    • 创建一个字符串对象,内容为字符串s
    • 示例:
    string str("hello");
    
    由于单参数构造函数支持类型转换,也可以写为:
    string str = "hello";
    

  1. 重载构造函数:string(const char* s, size_t n)
    • 创建一个字符串对象,内容为字符串s的前n个字符。
    • 示例:
    string str("hello", 3); //"hel"
    

  1. 重载构造函数:string(size_t n, char c)
    • 创建一个由n个字符c组成的字符串对象。
    • 示例:
    string str(5, 'a'); // "aaaaa"
    

除了以上构造函数,std::string类还提供了其他一些成员函数,这里不做详解,只列举几个常用的。


string的输入输出

operator<<

string<<进行了重载,我们可以直接对string对象使用<<,此时会输出这个string对象的字符串值。

示例:

string s1 = "hello world";
string s2 = " csdn";

cout << s1 << endl; //"hello world"
cout << s1 << s2 << endl; //"hello world csdn"

c_str

string还提供了一个函数,用于读取string对象中的字符串。

string s = "hello world";
cout << s.c_str() << endl; // "hello world"

这样看起来,c_str有点多此一举了,明明可以直接输出,不用c_str效果也是一致的。
其实不然,通过c_str还是和直接输出有差别的。

c_str的返回值是一个字符串,而<<对于字符串的输出机制是遇到'\0'中止输出。而string类重载的<<输出机制则是完整输出整个字符串,如果遇到'\0',会把'\0'一起输出。

看一个案例:

string s = "hello world \0 csdn";
cout << s.c_str() << endl; // "hello world "
cout << s << endl; // "hello world 0 csdn"

可以看到,通过s.c_str()输出,这个字符串没有被完整输出,只输出了'\0'前面的部分。而通过<<重载的输出,把整个字符串也输出了。

不够要注意,不同编译器对'\0'的输出方式不同,有的是当作0输出,有的忽略,还有的当作空格输出。


operator>>

同样的,string也对>>进行了重载,我们可以使用>>输入字符串。

string s1;
string s2;

cin >> s1 >> s2; // 输入"hello world"
cout << s1 << endl; // "hello"
cout << s2 << endl; // "world"

但是如果我们输入的字符串中包含空格,那么>>就不是很好用了:

string s;

cin >> s1; // 输入"hello world"
cout << s1 << endl; // "hello"

由于输入字符串时,遇到空格会中止读取,所以包含空格的字符串不能用这个方式输入,此时就要用getline了.


getline

getline可以获取一整行的字符串,包括空格,只有遇到换行符的时候才会中止。
不过要注意getline不是string类的成员函数,但是是string头文件的普通函数。
所以使用时不需要使用对象.getline()这样的格式,而是直接使用。

在这里插入图片描述

其第一个参数是istream的对象,比如cin
第二个参数是输入到的string对象。
第三个参数决定遇到什么字符的时候停止读取,默认值为'\n',即换行时停止读取。

示例:

string s;

getline(cin, s); // "hello world csdn"
cout << s << endl; // "hello world csdn"

string访问及遍历

operator[ ] & at

operator[ ] 和 at都是通过下标访问的成员函数,两者作用几乎一致。

在这里插入图片描述

示例:

string s = "hello world";

cout << s[2] << endl; // 'l'
cout << s[8] << endl; // 'r'

在这里插入图片描述

示例:

string s = "hello world";

cout << s.at(2) << endl; // 'l'
cout << s.at(8) << endl; // 'r'

两者的参数完全一致,即pos下标,传入这个参数后,输出下标位置的字符。此外,他们各自都提供了const版本的重构,用于const对象。
两者唯一的区别就是越界的情况:
operator[ ]越界时,会通过assert报错,直接中止程序。
at越界时,会抛出异常。


font & back

fontback用于返回字符串的首尾字符。

在这里插入图片描述
在这里插入图片描述

要注意,其返回值为引用返回char&,所以对其修改时,是会影响到原先的字符串的。


如果我们想遍历一个字符串,可以通过operator[ ] 或者 at,利用for循环来遍历,但是STL库还提供了迭代器,用于遍历对象。

迭代器
begin & end

在C++的string类中,beginend是两个成员函数,用于返回字符串的起始和结束迭代器。

在这里插入图片描述
begin函数返回一个迭代器,该迭代器指向字符串的第一个字符。可以使用解引用运算符*获取迭代器指向的字符。例如,*str.begin()将返回字符串中的第一个字符。

在这里插入图片描述

end函数返回一个迭代器,该迭代器指向字符串结尾的下一个位置。因此end()函数返回的迭代器不指向字符串中的任何字符。可以将end函数返回的迭代器与其他迭代器进行比较,以确定迭代器是否已达到字符串的末尾。

两者的返回类型都是iterrtor或者const_iterrtor,这个是迭代器的类型,后面结合案例讲解。

使用beginend函数可以遍历字符串中的所有字符。
接下来演示如何使用beginend函数遍历字符串中的字符并输出它们:

string str = "Hello World";
  
// 使用begin()和end()函数遍历字符串中的字符
string::iterrtor it = str.begin()
while(it != str.end())
{
	cout << *it;
	++it;
}

其中iterrtor是迭代器的类型,也是beginend的返回值类型。
当对象被const修饰时,那么其类型为const_iterrtor
平常可以直接用auto来代替这个类型。

所以以上代码可以写为:

string str = "Hello World";
  
// 使用begin()和end()函数遍历字符串中的字符
auto it = str.begin()
while(it != str.end())
{
	cout << *it;
	++it;
}

输出结果为:Hello World

在上面的示例中,使用begin函数获取指向字符串开头的迭代器,并使用end函数获取指向字符串结尾的迭代器。使用while循环遍历字符串中的每个字符,通过解引用*it将迭代器指向的字符输出到终端。

需要注意的是,end函数返回的迭代器指向的位置是一个越界的位置,不应该去解引用该迭代器,因为它指向的是无效的位置。


rbegin & rend

迭代器不仅支持正向遍历,还支持反向遍历,此时就需要反向迭代器rbegin,rend了。其中r代表reverse,反转的意思。
在这里插入图片描述
rbegin是一个反向迭代器,用于指向容器的最后一个元素,并向前迭代。

在这里插入图片描述

rendrbegin的逆操作。rbegin返回容器的最后一个元素的迭代器,而rend返回容器的第一个元素之前的位置的迭代器,这是一个越界的位置,同样不允许修改。

下面是一个例子,

string s1 = "54321";

string:reverse_iterator rit = s.begin();

while (rit != str.rend()) {
	cout << *rit << " ";
	++rit;
}

输出结果为:5 4 3 2 1

在上面的例子中,nums.rbegin()返回了指向最后一个元素的迭代器,而nums.rend()返回了指向第一个元素之前位置的迭代器。通过遍历这个范围内的元素,我们可以实现反向遍历。

注意:虽然这是一个反向迭代,但是我们的迭代器rit依然以++操作,而非--

当对象被const修饰时,那么rbeginrend的返回值类型为const_reverse_iterator


范围for

范围for循环也适用于string,其本质是基于迭代器的循环。

string s = "hello world";

for(auto ch : s)
{
	cout << ch;
}

以上代码输出"hello world"


string的容量操作

size & length

在这里插入图片描述
size返回当前字符串的长度。

在这里插入图片描述
length返回当前字符串的长度。

两者的作用完全一致,没有区别,那么为什么STL要设计两种方式来返回string对象的长度呢?

这是因为早期的string还不属于STL,使用length来表达长度,当string进入STL后,为了与其他的数据结构保持一致,都使用size来表示长度,于是又增加了一个size


max_size

在这里插入图片描述
string类中,max_size函数返回字符串对象的最大可能大小。这个值是由字符串对象所使用的内存分配器的最大分配限制决定的。

让我们通过一个例子来说明:


string myString;
   
cout << myString.max_size() << endl;

在这个例子中,我们创建了一个空的字符串对象myString,然后使用max_size函数来获取最大字符串大小。

请注意,max_size函数返回的是一个表示可能的最大大小的值,并不一定意味着可以确保分配这么多内存。实际上,这个值通常会受到计算机系统内存限制的限制。

例如,如果你的系统内存限制为4GB,那么max_size()函数返回的值可能是231-1 (约为2GB),因为这是系统能够分配的最大内存大小。


capacity

在这里插入图片描述
capacity函数用于返回字符串的当前容量(当前可以存储的最大字符数)。

string str = "Hello World";
    
cout << "当前容量:" << str.capacity() << endl;

clear

在这里插入图片描述

在string类中,clear函数用于清空字符串内容,并将字符串的长度设置为0。
下面是一个示例:

string str = "Hello, World!";
cout << "原始字符串: " << str << endl;

str.clear();
cout << "清空后的字符串: " << str << endl;

在上面的例子中,首先我们创建了一个名为strstring对象,并将其初始化为"Hello, World!"。然后我们使用clear函数将字符串内容清空,最后我们打印输出清空后的字符串,可以看到输出结果为空字符串。


empty

在这里插入图片描述
empty函数用于检查一个字符串是否为空,即字符串中是否没有任何字符。该函数返回一个bool类型的值。

示例:

string str1 = "Hello";
string str2 = "";

if (str1.empty()) 
{
	cout << "str1 is empty" << endl;
} 

if (str2.empty()) 
{
	cout << "str2 is empty" << endl;
} 

在上面的代码中,我们创建了两个字符串变量str1str2,并分别初始化为"Hello"和""(空字符串)。

接着,我们使用empty()函数来检查这两个字符串是否为空。如果字符串为空,则输出相应的提示信息。

运行上述代码,输出结果为:

str1 is not empty
str2 is empty

可以看到,由于str1中有字符,所以str1.empty()返回false,而str2中没有字符,所以str2.empty()返回true。


reserve

在这里插入图片描述reserve是一个用来预留字符串容量的方法。

reserve方法的目的是为了避免频繁的内存分配和释放操作,提高程序的效率。当我们使用string对象时,由于字符串的长度是可变的,所以在进行增删改等操作时,可能会导致内存重新分配,这会带来一定的时间开销。

为了避免这种情况,我们可以使用reserve方法来预先分配足够的内存空间。
示例:

string str;
cout << "初始容量: " << str.capacity() << endl;
    
str.reserve(100); // 预分配100个字符的容量
cout << "预分配后容量: " << str.capacity() << endl;
    
str = "Hello, World!";
cout << "赋值后容量: " << str.capacity() << endl;

输出结果为:

初始容量: 15
预分配后容量: 100
赋值后容量: 100

在这个示例中,我们首先创建了一个空的字符串str。通过调用capacity方法,我们可以查看当前字符串的容量。初始容量为15,这是字符串的初始默认容量。

接下来,我们调用reserve方法,预分配了100个字符的容量。通过再次调用capacity方法,我们可以看到预分配后的容量变为了100。

然后,我们将字符串赋值为"Hello, World!",并再次调用capacity方法。在这种情况下,预分配的容量没有发挥作用,因为字符串的长度并没有超过预分配的容量。所以赋值后的容量仍然为100。

通过使用reserve方法,我们可以在需要频繁操作字符串的情况下,提前预分配足够的内存空间,以避免不必要的内存分配和释放操作,从而提高程序的效率。


resize

在这里插入图片描述
resize函数用于改变字符串的大小。它可以增加或减少字符串的长度。

resize函数有两个参数,第一个参数是新的字符串长度,第二个参数是填充字符(可选)。如果新的长度小于当前长度,则字符串会被截断如果新的长度大于当前长度,则字符串会自动增加大小,并用指定的填充字符填充空白部分,如果没有选定字符,则默认用\0填充

下面的例子将演示如何使用resize函数。

string str = "Hello World!";
    
// 将字符串的长度改为10
str.resize(10);
cout << str << endl;

// 将字符串的长度改为15
str.resize(10);
cout << str << endl;
    
// 将字符串的长度增加到20,并用字符'+'填充空白部分
str.resize(20, '+');
cout << str << endl;

输出结果为:

Hello Worl
Hello Worl
Hello Worl++++++++

在上面的例子中,我们首先将字符串的长度改为10,超过10个字符的部分将被截断。
输出前10个字符Hello Worl
然后,我们将字符串的长度增加到15,此时没有传入第二个参数,此时用\0填充多出来的部分。
输出前15个字符,但是由于\0会被忽略,所以最后输出Hello Worl
最后将长度改为20,并用字符’+'填充空白部分。
输出Hello Worl++++++++

要注意的是,就算使用resizesize缩小,capacity容量大小不会减小,而是保持原本的大小


shrink_to_fit

在这里插入图片描述
shrink_to_fit函数用于将string对象的容量缩减为其实际大小。这个函数可以减少string对象的内存占用。

示例:

string str = "This is a long string that will be shortened.";
cout << "size before shrink: " << str.size() << endl;
cout << "capacity before shrink: " << str.capacity() << endl;

str.resize(10); // 缩减字符串的大小为10个字符
cout << "size after resize: " << str.size() << endl;
cout << "capacity after resize: " << str.capacity() << endl;

str.shrink_to_fit(); // 将字符串的容量缩减为实际大小
cout << "size after shrink: " << str.size() << endl;
cout << "capacity after shrink: " << str.capacity() << endl;

输出结果:

size before shrink: 45
capacity before shrink: 50

size after resize: 10
capacity after resize: 50

size after shrink: 10
capacity after shrink: 13

在上面的例子中,我们首先创建一个包含45个字符的string对象。然后,我们使用resize函数将字符串的大小缩减为10个字符。接下来,我们使用shrink_to_fit函数将字符串的容量缩减为实际大小。最后,我们通过调用sizecapacity函数来查看字符串的大小和容量。

可以看到,在调用shrink_to_fit函数之后,字符串的容量从之前的50缩减为13,与实际大小相匹配。


string的修改操作

push_back

在这里插入图片描述

push_back函数用于将字符添加到字符串的末尾。它接受一个字符作为参数,并将其追加到字符串的末尾。

示例:

string str = "Hello";
    
str.push_back(' '); // 添加一个空格字符到字符串的末尾
str.push_back('W');
str.push_back('o');
str.push_back('r');
str.push_back('l');
str.push_back('d');
    
cout << str << endl; // 输出 "Hello World"

在上面的示例中,我们首先创建了一个名为str的字符串,并将其初始化为"Hello"。然后我们使用push_back函数多次将字符添加到字符串的末尾。输出"Hello World"

注意:push_back函数只接受一个字符作为参数,如果传递一个字符串或其他类型的参数,将会引发编译错误


append

在这里插入图片描述

string类中的append方法用于将一个字符串追加到另一个字符串的末尾。它有多个重载版本,可以接受不同类型的参数作为输入。

基本使用:

string str1 = "Hello";
string str2 = " World!";
    
// 使用append方法将str2追加到str1的末尾
str1.append(str2);
    
cout << str1 << endl;  // 输出 "Hello World!"

在上面的例子中,我们首先创建了两个字符串变量str1str2,分别初始化为"Hello"和" World!"。然后,我们使用str1append方法将str2追加到str1的末尾。最后,我们将str1输出到控制台,得到的结果是"Hello World!"

append方法还可以接受其他类型的参数作为输入,例如const char*charstd::stringstd::initializer_list<char>等。下面是一些使用不同参数类型的案例:

string str1 = "Hello";
    
// 使用char*类型的参数
str1.append(" World!");
    
cout << str1 << endl;  // 输出 "Hello World!"
    
string str2 = "Hello";
// 使用char类型的参数
str2.append(3, 'w');

cout << str2 << endl;  // 输出 "Hellowww!"
string str3 = "Hello";

// 使用string类型的参数
string str4 = " World!";
str3.append(str4);

cout << str3 << endl;  // 输出 "Hello World!"

在上面的例子中,我们分别使用char*类型的参数、char类型的参数和string类型的参数来调用append方法。无论参数类型是什么,append方法都会将其追加到字符串的末尾,实现字符串的拼接操作。


operator+=

在这里插入图片描述
operator+=是用于将一个字符串追加到另一个字符串的末尾的运算符重载。

根据其三个重载可以看出来,operator+=可以追加string对象,字符串,字符三种类型,功能全面,语法简单,比appendpush_back好用的多。

示例:
追加string对象:

string s1 = "hello";
string s2 = " world";

//追加string对象
s1 += s2;
cout << s1 << endl; //"hello world”

追加字符:

string s = "hello world”;

s += '!';
cout << s << endl; //"hello world!”

追加字符串:

string s1 = "hello";

//追加string对象
s1 += " world";
cout << s1 << endl; //"hello world”

实际中推荐使用这个运算符重载替代appendpush_back


insert

在这里插入图片描述

insert函数可以用于在字符串中插入字符、子串或其他类型的数据。

通过函数重载可以看出,我们可以插入字符,字符串,string对象等。

插入字符串:

string str = "Hello, world!";

// 在指定位置插入字符串
str.insert(5, "!!!"); // 在位置5插入"!!!"
cout << str << endl;

输出结果为:Hello!!!, world!

插入字符:

string str = "Hello, world!";

// 在指定位置插入字符串
str.insert(5, 3, '!'); // 在位置5插入3个'!'
cout << str << endl;

输出结果为:Hello!!!, world!

注意:插入字符时,第二个参数是插入字符的个数,哪怕只插入一个字符,这个值也不能缺省

插入string对象:

string str1 = "Hello, world!";
string str2 = "!!!";

// 在指定位置插入字符串
str.insert(5, str2); // 在位置5插入str2
cout << str << endl;

输出结果为:Hello!!!, world!


erase

在这里插入图片描述

erase函数可以用来删除字符串中的字符或子字符串。

首先,我们来看一个简单的示例,删除字符串中的一个字符:

string str = "Hello World";
str.erase(4); // 删除第5个字符,即空格
cout << str << endl; // 输出 "HelloWorld"

在这个例子中,我们创建了一个字符串"Hello World",然后使用erase函数删除了第5个字符,即字符串中的空格。最后输出的结果是"HelloWorld"

接下来,让我们来看一个稍微复杂一些的例子,删除字符串中的一个子字符串:

string str = "Hello World";
str.erase(6, 5); // 从第7个字符开始,删除5个字符,即"World"
cout << str << endl; // 输出 "Hello"

在这个例子中,我们同样创建了一个字符串"Hello World",然后使用erase函数删除了从第7个字符开始的5个字符,即字符串中的"World"。最后输出的结果是"Hello"

除了上述两种用法外,erase函数还可以接受迭代器作为参数,用来删除指定范围内的字符或子字符串。下面是一个例子:

string str = "Hello World";
string::iterator start = str.begin() + 6; // 第7个字符的迭代器
string::iterator end = str.begin() + 11; // 第12个字符的迭代器
str.erase(start, end); // 删除从第7个字符到第12个字符的子字符串,即"World"
cout << str << endl; // 输出 "Hello "

在这个例子中,我们同样创建了一个字符串"Hello World",然后使用迭代器指定了要删除的子字符串的范围,即从第7个字符到第12个字符。最后输出的结果是"Hello "(注意,这里输出结果后面还有一个空格,因为我们只删除了子字符串,而没有删除空格字符)。


replace

在这里插入图片描述

replace函数用于在字符串中替换指定的子字符串。

假设我们有一个字符串str,其内容为"Hello, World!“,我们想要将其中的"World"替换为"Universe”。我们可以使用string类的replace函数来实现。

string str = "Hello, World!";
    
cout << "原始字符串: " << str << endl;
    
    // 使用replace函数替换字符串
str.replace(str.find("World"), 5, "Universe");
    
cout << "替换后的字符串: " << str << endl;

在上述代码中,我们使用了string类的replace函数。该函数有三个参数:要替换的起始位置、要替换的字符个数、以及替换的字符串。

在本例中,我们使用str.find(“World”)来查找字符串中"World"的起始位置,返回值是一个整数表示位置。接着,我们指定要替换的字符个数为5,即"World"的长度。最后,我们将要替换的字符串指定为"Universe"。

编译并运行上述代码,输出结果应为:

原始字符串: Hello, World!
替换后的字符串: Hello, Universe!

可以看到,replace函数将原始字符串中的"World"替换为了"Universe",并输出了替换后的字符串。

此外,通过函数重载可以看出,其支持替换字符,通过迭代器替换字符串等等操作,这里不做展开,


swap

在这里插入图片描述

swap函数用于交换两个string对象之间的内容。

示例:

string str1 = "Hello";
string str2 = "World";
 
str1.swap(str2);
    
cout << "After swap:" << endl;
cout << "str1: " << str1 << endl;
cout << "str2: " << str2 << endl;

在上面的代码中,我们创建了两个string对象str1str2,并将它们初始化为"Hello""World"。然后我们使用swap函数将两个字符串的内容进行了交换。最后输出交换后的结果,我们可以看到str1的值变成了"World",而str2的值变成了"Hello"

在C++标准库中,有一个非成员的swap函数被定义在<std>头文件中,用于交换两个对象的值。
现在让我们将string类中的swap函数与std命名空间中的swap函数进行对比。

下面是一个示例,展示如何使用std中的swap()函数:

string str1 = "Hello";
string str2 = "World";
    
swap(str1, str2);
    
cout << "After swap:" << std::endl;
cout << "str1: " << str1 << endl;
cout << "str2: " << str2 << endl;

在这个例子中,我们使用了std命名空间中的swap函数,将str1str2的内容进行了交换。输出的结果与前一个例子是一样的。

但是std中的swap将两个对象完全交换了,这个过程创建了string类型的中间变量

而string中的swap并没有完全交换对象,只是交换了两个对象的指针,以及值,并没有创建string类型的中间变量

所以对于string对象,使用string自带的swap效率会更高


string的查找操作

find

在这里插入图片描述
find函数用于在字符串中查找子字符串的第一次出现。

find函数接受两个参数:
待查找的子字符串 str 或者字符c
开始搜索的位置 pos(可选,默认值为0)

返回值:

  • 如果找到了指定子串,返回它在原字符串中第一次出现的位置。
  • 如果未找到指定子串,返回string::npos

示例:

string str = "Hello World";
string subStr = "World";

// 使用find函数查找子字符串的位置
size_t index = str.find(subStr);

cout << "子字符串在位置 " << index << " 处被找到" << endl;

以上示例中,我们定义了一个字符串 str 和一个子字符串 subStr。然后使用find函数在str中查找subStr,并将返回的位置存储在index变量中。最后,我们通过判断index是否等于std::string::npos来确定是否找到了子字符串。

输出结果为:"子字符串在位置 6 处被找到",因为子字符串"World"在字符串"Hello World"的第6个位置开始出现。


refind

在这里插入图片描述rfind用于在字符串中寻找指定子串的最后一次出现的位置,或者说是倒着查找

rfind函数接受两个参数:
待查找的子字符串 str 或者字符c
开始搜索的位置 pos(可选,默认为string::npos

返回值:

  • 如果找到了指定子串,返回它在原字符串中最后一次出现的位置。
  • 如果未找到指定子串,返回string::npos

下面是一个示例代码,演示了如何使用rfind函数:

string str = "hello world, hello C++";
string subStr = "hello";

size_t found = str.rfind(subStr);
cout << "Found at position: " << found << endl;

运行结果为:

Found at position: 13

在上面的示例中,我们定义了一个字符串str,然后使用rfind函数在字符串中查找子串"hello"的最后一次出现的位置。由于"hello"字符串最后一次出现在位置13,所以found的值为13,并输出"Found at position: 13"


sub_str

在这里插入图片描述
substr用于提取字符串的子串。该函数可以接受两个参数,起始索引位置和子串的长度。

示例:

string str = "Hello, world!";

// 提取从索引位置3开始的子串
string sub1 = str.substr(3);

// 输出子串
cout << sub1 << endl; // 输出为 "lo, world!"

// 提取从索引位置7开始长度为5的子串
std::string sub2 = str.substr(7, 5);

// 输出子串
cout << sub2 << endl; // 输出为 "world"

在上面的示例代码中,我们首先创建了一个字符串 str,然后使用 substr() 函数提取了两个不同的子串。第一个 substr() 函数调用中,指定了起始索引位置为3,没有指定长度,因此提取从索引位置3开始到字符串末尾的子串。第二个 substr() 函数调用中,指定了起始索引位置为7和长度为5,因此提取了从索引位置7开始长度为5的子串。

运行程序,输出结果为:

lo, world!
world

可以看到,substr() 函数成功提取了指定位置和长度的子串,并将其存储在新的字符串变量中。


find_first_of & find_first_not_of

在这里插入图片描述
find_first_of函数用于在字符串中查找第一个与指定字符序列中的任意字符匹配的字符的位置

find_first_of函数有多个重载形式,其中最常用的形式如下:

size_t find_first_of (const string& str, size_t pos = 0) const;

这个函数接受一个字符串参数str,并从指定的位置pos开始搜索。find_first_of函数会在调用对象的字符串中查找第一个与str中的任意字符匹配的字符,并返回其位置。如果找不到匹配的字符,则返回string::npos

下面是一个示例:

string str = "Hello World";
string chars = "aeiou";

// 在str中查找第一个出现在"aeiou"中的字符
size_t pos = str.find_first_of(chars);
 
cout << "第一个元音字母出现在位置:" << pos << endl;
cout << "字符为:" << str[pos] << endl;

输出结果为:

第一个元音字母出现在位置:1
字符为:e

在上面的示例中,我们定义了一个字符串str和一个字符串chars,其中chars包含了要查找的字符序列,即元音字母。然后,我们使用find_first_of函数在str中查找第一个出现的元音字母的位置,并将结果存储在变量pos中。最后,我们根据pos的值输出结果。

注意,find_first_of函数还有其他的重载形式,可以接收更多参数,如指定搜索的区间等,这里不做详解。以上是其中最常用的一种形式,更详细的使用方式可以参考C++的官方文档或相关教程。

find_first_not_of则是查找在目标字符串中的字符。
比如:

size_t pos = str.find_first_not_of("aeiou");

就是在str中查找第一个不存在于"aeiou"中字符。


find_last_of & find_last_not_of

在这里插入图片描述
first对应的就是last,也就是从后往前找,性质是一样的,这里简单讲解一个案例:

string str = "Hello World";
string chars = "aeiou";

// 在str中查找最后一个出现在"aeiou"中的字符
size_t pos = str.find_last_of(chars);
 
cout << "最后一个元音字母出现在位置:" << pos << endl;
cout << "字符为:" << str[pos] << endl;

输出结果为:

最后一个元音字母出现在位置:7
字符为:o

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

用甘特图有效管理多个项目进度

当公司或组织同时承担多个项目时,合理规划各项目的时间节点与资源分配对确保高效完成至关重要。采用甘特图可以直观地展示多个项目的时间进程、关键里程碑以及资源分配情况,便于从宏观层面全面把控各项目的动态。 在线甘特图软件 zz-plan.com 提供了非常强大的时间轴规划功能,支…

CSS 多色正方形上升

<template><view class="loop cubes"><view class="item cubes"></view> <!-- 方块1 --><view class="item cubes"></view> <!-- 方块2 --><view class="item cubes"></vie…

C# 将HTML网页、HTML字符串转换为PDF

将HTML转换为PDF可实现格式保留、可靠打印、文档归档等多种用途&#xff0c;满足不同领域和情境下的需求。本文将通过以下两个示例&#xff0c;演示如何使用第三方库Spire.PDF for .NET和QT插件在C# 中将Html 网页&#xff08;URL&#xff09;或HTML字符串转为PDF文件。 HTML转…

【C语言】深入理解指针(3)数组名与函数传参

目录 &#xff08;一&#xff09;数组名的理解 &#xff08;1&#xff09;数组名是数组首元素的地址 &#xff08;2&#xff09;两个例外 &#xff08;二&#xff09;函数内数组传参 &#xff08;1&#xff09;一维数组传参 &#xff08;2&#xff09;二维数组传参 &…

以太网交换基础VLAN原理与配置

目录 7.以太网交换基础 7.1.以太网协议 7.2.以太网帧介绍 7.3.以太网交换机 7.4.同网段数据通信全过程 8.VLAN原理与配置 8.1.VLAN的基本概念 8.2.VLAN的应用 7.以太网交换基础 7.1.以太网协议 以太网是当今现有局域网(Local Area Network,LAN)采用的最通用的通信协议…

git使用指南——以gitlab为例

注册gitlab 自行注册 新建项目 选择新建一个空白的项目 上传项目 clone项目地址到本地 执行完之后&#xff0c;会在目录下生成如下内容&#xff1a;进入里面&#xff0c;选择.git&#xff0c;要上传的内容&#xff08;资料或代码复制到该目录下&#xff09;&#xff1a;…

界面组件DevExpress .NET MAUI中文教程 - 如何优化手机屏幕空间?

DevExpress拥有.NET开发需要的所有平台控件&#xff0c;包含600多个UI控件、报表平台、DevExpress Dashboard eXpressApp 框架、适用于 Visual Studio的CodeRush等一系列辅助工具。 获取DevExpress v23.2正式版下载 Bottom Sheet是一个组件&#xff0c;它显示固定在屏幕底部的…

LeetCode:376.摆动序列

个人主页&#xff1a;仍有未知等待探索-CSDN博客 专题分栏&#xff1a;算法_仍有未知等待探索的博客-CSDN博客 题目链接&#xff1a;376. 摆动序列 - 力扣&#xff08;LeetCode&#xff09; 一、题目 如果连续数字之间的差严格地在正数和负数之间交替&#xff0c;则数字序列称…

【排序5】基数排序:数字的组织与整理艺术

&#x1f3a1;基数排序 &#x1f38a;1、基本思想&#x1f38a;2、基本步骤&#x1f38a;3、代码示例&#x1f38a;4、特性总结 &#x1f38a;1、基本思想 基数排序&#xff08;Radix Sort&#xff09;是一种非比较排序算法&#xff0c;它根据数字的每一位来对元素进行排序。它…

提示unzip :commad not found; 安装unzip教程

1.当使用unzip解压时 提示&#xff1a; unzip :commad not found; 2.安装命令 sudo yum install unzip 3.输入 y 确认 4.提示&#xff1a;完成 5.输入 unzip 文件名 解压-验证 6.完成

34.基于51单片机的智能停车位计时收费系统设计

一、系统功能介绍&#xff1a; 本设计基于 RFID智能识别和高速的视频图像和存储比较相结合&#xff0c;通过计算机的图像处理和自动识别&#xff0c;对车辆进出停车场的收费、车牌识别和车位诱导等&#xff0c;以实现停车场全方位智能管理。 本设计是以AT89C51 型单片机为主控芯…

Kubernetes (十七) 资源监控

一. 资源监控 二. metrics-server资源下载配置 官网:资源下载&#xff1a;http…

搭建Mybatis环境

1.导入依赖 pom.xml <dependencies> <!-- Mybatis依赖--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.7</version></dependency> <!-- Mysql依…

Tonka Finance 测试网活动,开启新铭文时代财富之门

Tonka Finance 是铭文赛道首个借贷市场&#xff0c;通过搭建一套铭文资产借贷质押方案&#xff0c;为铭文资产以借贷的形式释放价值、捕获流动性等方面提供了基础。作为铭文赛道最重要的基建设施之一&#xff0c;Tonka Finance 在面向市场后备受关注&#xff0c;并迅速作为铭文…

【UE】在控件蓝图中通过时间轴控制材质参数变化

效果 步骤 1. 新建一个控件蓝图和一个材质 2. 打开材质&#xff0c;设置材质域为用户界面&#xff0c;混合模式设置为“半透明” 在材质图表中添加两个参数来控制材质的颜色和不透明度 3. 对材质创建材质实例 4. 打开控件蓝图&#xff0c;在画布面板中添加一个图像控件 将刚…

vue常用指令(v-html)

一、v-html 指令 作用: 获取文本数据设置元素的innerHTML&#xff0c;此为和v-text的区别 二、代码演示 1、获取普通文本数据 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><meta name"viewpor…

32个Java面试必考点-08高并发架构基石-缓存

本课时介绍缓存相关的知识点以及 Memcache 和 Redis 这两个最常使用的缓存。重点学习以下三个方面的内容&#xff1a; 1.使用缓存时常遇到的典型问题&#xff1b; 2.Memcache 的内存结构&#xff1b; 3.Redis 相关的知识点以及 Redis 常用结构的实现。 缓存知识点 类型 缓…

day34WEB 攻防-通用漏洞文件上传黑白盒审计逻辑中间件外部引用

目录 一&#xff0c;白盒审计-Finecms-代码常规-处理逻辑 黑盒思路&#xff1a;寻找上传点抓包修改突破获取状态码及地址 审计流程&#xff1a;功能点-代码文件-代码块-抓包调试-验证测试 二&#xff0c;白盒审计-CuppaCms-中间件-.htaccess 三&#xff0c;白盒审计-Metin…

XCTF:Normal_RSA[WriteUP]

从题目中获取到两个文件 flag.enc内容是通过rsa加密了的密文 pubkey.pem是rsa公钥&#xff0c;加密者利用这个文件对flag原文进行了加密 如果对rsa加密算法不了解的可以补一下教学视频 数学不好也能听懂的算法 - RSA加密和解密原理和过程_哔哩哔哩_bilibili 使用openssl对公…

使用dockers-compose搭建开源监控和可视化工具

简介 Prometheus 和 Grafana 是两个常用的开源监控和可视化工具。 Prometheus 是一个用于存储和查询时间序列数据的系统。它提供了用于监控和报警的数据收集、存储、查询和图形化展示能力。Prometheus 使用拉模型&#xff08;pull model&#xff09;&#xff0c;通过 HTTP 协议…