C++ stl容器之string(字符串类)

article/2025/6/8 10:33:36

目录

(0)string和char *的区别

(1)string类对象的构造

(2)容量操作

(3)访问遍历

1.用下标访问和遍历

2.用迭代器访问和遍历

①迭代器说明

②迭代首尾注意事项

③使用举例

3.用"范围for"访问和遍历(c++11特性)

4.用for+auto关键字(c++11特性)

(4)增删改查

1.相关接口说明

2.使用例子

3.一些细节说明

①push_back优化插入数据效率

②find和rfind说明

③npos说明

④find_first_of()和find_last_of()

⑤linux环境下c_str()问题

⑥substr说明

⑦replace替换

⑧erase删除

⑨insert插入

(5)牛刀小试

1.仅仅反转字母

2.字符串中的第一个唯一字符

3.字符串最后一个单词的长度

4.验证回文串

5.整数字符串相加

(6)c++中string的assign方法使用

(7)string常用算法

(8)相关工具函数

去掉两端空格

获取子串出现的次数


(0)string和char *的区别

string是STL的字符串类型,通常用来表示字符串。而在使用string之前,字符串通常是用char*表示的。string与char*都可以用来表示字符串,那么二者有什么区别呢:

  • string是一个类,,char*是一个指向字符的指针。string封装了char*,管理这个字符串,是一个char*型的容器。
  • string不用考虑内存释放和越界。string管理char*所分配的内存。每一次string的复制,取值都由string类负责维护,不用担心复制越界和取值越界等。
  • string提供了一系列的字符串操作函数,比如查找find,拷贝copy,删除erase,替换replace,插入insert

(1)string类对象的构造

#include <iostream>
#include <string>
using namespace std;int main()
{// 1.构造空的string类对象s1string s1;// 2.用C格式字符串构造string类对象s2             string s2("hello world"); string s3 = "hello world";// 3.拷贝构造string s4(s2); // 地址都不相同printf("%p,%p,%p", &s2, &s3, &s4); // 000000000061fdc0,000000000061fda0,000000000061fd80// 4.初始化由n个相同字符组成的字符串string s6(4, '6');          string s7 = string(4, '7'); // 5.将s6赋值给s1s1.assign(s6);  // 6.将数组直接赋值给stringchar name[7] = "601669";string x = name;cout << x.c_str() << endl;  // 601669cout << x.size() << endl;   // 6return 0;
}

(2)容量操作

常用容量属性/方法

  • size 返回字符串有效字符长度
  • length 返回字符串有效字符长度
  • capacity 返回空间总大小
  • empty 检测字符串是否为空串,是返回true,否则返回false
  • clear 清空有效字符
  • reserve 改变字符串空间总大小,即为string预留空间
  • resize 将有效字符的个数改成n个,多出的空间用字符c填充

说明

  • size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一致,一般情况下基本都是用size()。
  • clear()只是将string中有效字符清空,不改变底层空间大小。
  • resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用0来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。
  • resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。
  • reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数。

用法举例

#include <iostream>
#include <string>
using namespace std;int main()
{string s1 = "hello world";cout << s1 << endl;cout << s1.size() << endl;     // 11cout << s1.length() << endl;   // 11cout << s1.capacity() << endl; // 15// 将s1中的字符串清空,注意清空时只是将size清0,不改变底层空间的大小cout << "---------------------" << endl;s1.clear(); // 空cout << s1 << endl;cout << s1.size() << endl;     // 0cout << s1.capacity() << endl; // 15// 判断是否为空字符串if (s1.empty())cout << "s1 = empty" << endl; // s1 = emptyelsecout << "s1 != empty" << endl;string s2;if (s2.empty())cout << "s2 = empty" << endl; // s2 = emptyelsecout << "s2 != empty" << endl;// 将s1中有效字符个数增加到20个,多出位置用'a'进行填充cout << "---------------------" << endl;s1.resize(20, 'a');cout << s1 << endl;            // aaaaaaaaaaaaaaaaaaaacout << s1.size() << endl;     // 20cout << s1.capacity() << endl; // 30// 将s1中有效字符个数减少到15个cout << "---------------------" << endl;s1 = "hello world study hard";s1.resize(15);cout << s1 << endl;            // hello world stucout << s1.size() << endl;     // 15cout << s1.capacity() << endl; // 30// 测试reserves1.reserve(100);cout << s1.size() << endl;     // 15 //说明不会改变string中有效元素个数cout << s1.capacity() << endl; // 100s1.reserve(50);cout << s1.size() << endl;     // 15cout << s1.capacity() << endl; // 50return 0;
}

(3)访问遍历

1.用下标访问和遍历

#include <iostream>
#include <string>
using namespace std;int main()
{// 1.直接下标访问string s1("hello world");const string s2("Hello world");cout << s1 << "   " << s2 << endl;     cout << s1[0] << " " << s2[0] << endl; s1[0] = 'H';cout << s1 << endl; // Hello world// 2.使用for遍历所有字符string s("hello world");for (size_t i = 0; i < s.size(); ++i)cout << s[i];cout << endl;return 0;
}

2.用迭代器访问和遍历

①迭代器说明

迭代器是一种抽象的概念,它类似于指针,但比指针更加通用和安全。迭代器封装了底层数据结构的访问细节,为算法提供了一种统一的接口来遍历和操作容器中的元素。通过迭代器,算法可以无需关心容器的具体实现细节,只需按照迭代器的规则进行操作即可。

对于容器而言,每个位置的数据都对应一个迭代器。

迭代器有很多种类,这里以正向迭代器为例说明,现在我们有字符串对象s,常见操作如下

// 获取首位置的迭代器
string::iterator it = s.begin()// 获取迭代器指向位置的数据
cout << *it;// 获取末位置的迭代器
string::iterator it = s.end()// 用迭代器遍历全部数据
string::iterator it = s.begin()
while (it != s.end()) {cout << *it;++it;
}

②迭代首尾注意事项

这里还有一个细节,这个首尾具体指的哪一个数据?见下图

③使用举例

#include <iostream>
#include <string>
using namespace std;int main()
{string s("hello world");// 1.正向迭代器访问和遍历string::iterator it = s.begin();while (it != s.end()){cout << *it;++it;}cout << endl;// 2.反向迭代器访问和遍历string::reverse_iterator rit = s.rbegin(); while (rit != s.rend()){cout << *rit;++rit;}cout << endl;// 3.改值string::iterator tp = s.begin();string::iterator &tmp = tp;while (tmp != s.end()){(*tmp)++;++tmp;}cout << s << endl;return 0;
}

3.用"范围for"访问和遍历(c++11特性)

#include <iostream>
#include <string>
using namespace std;int main()
{string s("hello world");// 普通使用for (char e: s) {cout << e;}cout << endl;// 加上引用for (char &e : s){e += 1;}// 再加一个const,变为不可修改for (const char &e : s)cout << e;cout << endl;return 0;
}

4.用for+auto关键字(c++11特性)

用auto,自动判断类型,更加灵活高级

#include <iostream>
#include <string>
using namespace std;int main()
{string s("hello world");// 可修改for (auto &e : s){e += 1;}// 不可修改for (const auto &e : s)cout << e;cout << endl;return 0;
}

(4)增删改查

1.相关接口说明

函数名称

功能与用法

push_back

在字符串后尾插字符c

append

在字符串后追加一个字符串

  • append(const char *s);    //把字符串s连接到当前字符串结尾
  • append(const char *s,int n);  //把字符串s的前n个字符连接到当前字符串结尾
  • append(const string &s);   //同operator+=()
  • append(const string &s,int pos, int n);//把字符串s中从pos开始的n个字符连接到当前字符串结尾
  • append(int n, char c);   //在当前字符串结尾添加n个字符c

operator+=

(常用) 在字符串后追加字符串str。string和string,string和字符数组可直接相加。对string操作时,如果能够大概预估到放多少字符,可以先通过reserve把空间预留好。

c_str

(常用) 返回C格式字符串

结合npos进行find

(常用) 从字符串pos位置(默认开始位置)开始往后找字符c,返回该字符在字符串中的位置。找不到时返回std::string::npos

rfind

从字符串pos位置(默认最后面)开始往前找字符c,返回该字符在字符串中的位置

substr

在str中从pos位置开始,截取n个字符,然后将其返回

erase

erase(int pos=0, int n=npos);  //删除pos开始的n个字符,返回修改后的字符串

replace

字符串的替换

replace(int pos, int n, const char *s);//删除从pos开始的n个字符,然后在pos处插入串s

replace(int pos, int n, const string &s);  //删除从pos开始的n个字符,然后在pos处插入串s

swap

void swap(string &s2);    //交换当前字符串与s2的值

2.使用例子

#include <iostream>
#include <string>
using namespace std;int main()
{string str;// 1.追加操作str.push_back(' ');                // 在str后插入空格cout << "(" << str << ")" << endl; // ( )str.append("Hello");               // 在str后追加一个字符"Hello"str += 'X';                        // 在str后追加一个字符'X'str += "world";                    // 在str后追加一个字符串"world"cout << "(" << str << ")" << endl; // ( HelloXworld)// 2.c_str 的意义cout << "(" << str.c_str() << ")" << endl; // 以C语言的方式打印字符串printf("(%s)\n", str.c_str());             // c_str 的意义// printf("%s\n", str); // 类型不匹  乱码// 3.用rfind和substr获取file的后缀string file("string.cpp");size_t pos = file.rfind('.');cout << pos << endl; // 6string suffix(file.substr(pos, file.size() - pos));cout << suffix << endl; //.cpp// 4. npos// npos是string里面的一个静态成员变量// static const size_t npos = -1;// string::npos是一个静态成员常量,表示size_t的最大值// std::string::npos// 该值表示直到字符串结尾,作为返回值它通常被用作表明没有匹配。// 5.用find、npos和substr取出url中的域名string url("http://www.cplusplus.com/reference/string/string/find/");cout << url << endl;string key("://");size_t start = url.find(key); // 如果找到返回第一个字符所在位置if (start == string::npos)    // 没有找到 返回的是nposcout << "invalid url" << endl;else{string result(url.substr(start + key.size(), url.size() - start - key.size()));cout << result << endl; // www.cplusplus.com/reference/string/string/find/}// 6.用erase删除url的协议前缀size_t mypos = url.find("://");url.erase(0, mypos + 3);cout << url << endl; // www.cplusplus.com/reference/string/string/find/return 0;
}

3.一些细节说明

①push_back优化插入数据效率

当字符串空间总大小不够而需要追加字符时,会扩展一定容量

如果每次追加都要扩容一下,那么开销明显增大

可以利用reserve提前预备好足够的容量提高效率

#include <iostream>
#include <string>
using namespace std;// 利用reserve提高插入数据的效率,避免增容带来的开销
void TestPushBack()
{string s;size_t sz = s.capacity();cout << sz << endl;cout << "making s grow:\n";for (int i = 0; i < 100; ++i){s.push_back('c');if (sz != s.capacity()){sz = s.capacity();cout << "i = " << i << ", capacity changed: " << sz << '\n';}}
}void TestPushBackReserve()
{string s;s.reserve(100);size_t sz = s.capacity();cout << sz << endl;cout << "making s grow:\n";for (int i = 0; i < 100; ++i){s.push_back('c');if (sz != s.capacity()){sz = s.capacity();cout << "i = " << i << ", capacity changed: " << sz << '\n';}}
}int main()
{// 当字符串空间总大小不够而需要追加字符时,会扩展一定容量TestPushBack();// 提前准备好充足的容量TestPushBackReserve();return 0;
}

②find和rfind说明

  • int find(char c,int pos=0) const;  //从pos开始查找字符c在当前字符串的位置 
  • int find(const char *s, int pos=0) const;  //从pos开始查找字符串s在当前字符串的位置
  • int find(const string &s, int pos=0) const;  //从pos开始查找字符串s在当前字符串中的位置
  • int rfind(char c, int pos=npos) const;   //从pos开始从后向前查找字符c在当前字符串中的位置 
  • int rfind(const char *s, int pos=npos) const;
  • int rfind(const string &s, int pos=npos) const;

find函数如果查找不到,就返回std::string::npos(是-1)

rfind是反向查找的意思,如果查找不到, 返回std::string::npos(是-1)

使用例子

#include <iostream>
#include <string>
using namespace std;int main()
{string str = "hello world";size_t pos1 = str.find('o');size_t pos2 = str.rfind('o');cout << pos1 << endl; // 4cout << pos2 << endl; // 7size_t pos3 = str.find('o', 5); // 从第五个位置开始找cout << pos3 << endl;           // 7size_t pos4 = str.rfind('o', 5); // 从第五个位置开始找cout << pos4 << endl;           // 4return 0;
}

查看不到则返回std::string::npos

#include <iostream>
using namespace std;#include <string>int main()
{string xx = "601998,601669";cout << xx.find("601998") << endl; // 0cout << xx.find("123") << endl;    // 18446744073709551615if (xx.find("123") == std::string::npos){cout << "xxx" << endl;  // 会执行此语句}return 0;
}

③npos说明

string::npos是一个静态成员常量,表示size_t的最大值(Maximum value for size_t)。该值表示“直到字符串结尾”,作为返回值它通常被用作表明没有匹配。

string::npos是这样定义的:

static const size_type npos = -1;

因为string::size_type描述的是size,故需为无符号整数型类别。因为缺省配置为size_t作为size_type,于是-1被转换为无符号整数类型,npos也就成为了该类别的最大无符号值。不过实际值还是取决于size_type的实际定义类型,即无符号整型(unsigned int)的-1与无符号长整型(unsigned long)的-1是不同的。

如果对 -1表示size_t的最大值有疑问可以采用如下代码验证:

#include <iostream>
#include <limits>
#include <string>
using namespace std;int main()
{size_t npos = -1;cout << "npos: " << npos << endl;cout << "size_t max: " << numeric_limits<size_t>::max() << endl;
}

④find_first_of()和find_last_of()

find_first_of()函数

正向查找在原字符串中第一个与指定字符串(或字符)中的某个字符匹配的字符,返回它的位置。若查找失败,则返回npos。

  • string str=“abcdefab”;
  • cout<<str.find_first_of(“hce”)<<endl;//待查串hce第一个出现在原串str中的字符是c,返回str中c的下标2,故结果为2。第二个参数为0,默认从原串下标为0开始正向查。
  • cout<<str.find_first_of(“ab”,1)<<endl;//从下标为1开始查,待查串ab第一个出现在原串str中的字符是b,返回b的下标,结果为1。

find_last_of()函数

逆向查找在原字符串中最后一个与指定字符串(或字符)中的某个字符匹配的字符,返回它的位置。若查找失败,则返回npos。

  • string str=“abcdefab”;
  • cout<<str.find_last_of(“wab”)<<endl;//原串最后一个字符首先与待查子串的每一个字符一一比较,一旦有相同的就输出原串该字符的下标.。结果为b的下标7。第二个参数为0,默认为npos。
  • cout<<str.find_last_of(“wab”,5)<<endl;//从原串中下标为5开始逆向查找,首先f与待查子串每一字符比较,若有相同的就输出该字符在原串的下标。若一个都没有,就依次逆向比较,即e再与待查子串一一比较,直到原串的b与待查子串中的b相同,然后输出该b在原串的下标1。

find和find_first_of的区别

find()和rfind()可以说是完全匹配查询,而find_first_of()和find_last_of()可以说是部分匹配。 但它们的返回值都是原串某字符的下标,是无符号整数类型。如果待查为字符串的话,前者可以说是字符串与字符串的比较,后者可以说是字符与字符的比较。需要好好体会。

代码加深理解

#include<iostream>
using namespace std;int main()
{string str="abcdefab";cout<<str.find_first_of('a')<<endl;  // 0cout<<str.find_first_of("hce")<<endl;  // 2cout<<str.find_first_of("ab",1)<<endl;  // 1cout<<str.find_first_of('h')<<endl;  // npos,也就是-1cout<<str.find_first_of("hw")<<endl;  // npos。cout<<str.find_last_of("wab")<<endl;  // 7cout<<str.find_last_of("wab", 5)<<endl;  // 1cout<<str.find_last_of("fab",5)<<endl;  // 5cout<<str.find_last_of("fab",7)<<endl; // 7cout<<str.find_last_of("hwk")<<endl;  //npos。return 0;
}

⑤linux环境下c_str()问题

c_str()返回一个以'\0'结尾的字符串的首地址,但在linux下使用c_str()可能会出现一点问题,这里做了记录与解决办法:

问题描述:将string用.c_str()转化为C语言的字符串后,在字符最后可能会多出一个乱码

示例代码

#include <iostream>
using namespace std;
#include <string>
#include <cstring>void func(string code)
{cout << code << endl;cout << code.c_str() << endl;for (int i = 0; i < strlen(code.c_str()); i++){cout << "(" << code.c_str()[i] << ")" << endl;}
}int main()
{string testcode = "601998.SH";func(testcode);return 0;
}

错误结果如下,可以看到结尾多了一个乱码字符。然后就是因为多的这个乱码字符,导致在使用strcat(filepath, code.c_str())后再使用strcat(filepath, ".csv");出现了结果上的错误。

601998.SH
601998.SH
(6)
(0)
(1)
(9)
(9)
(8)
(.)
(S)
(H)
)

解决办法

根据实际需要判断string.c_str()的最后一个字符是不是乱码,通常若string.c_str()的长度比string长,则多出来的部分为乱码,则需将code.c_str()的最后一个字符或者倒数某个字符变成 0 或者'\0'

#include <iostream>
using namespace std;
#include <string>
#include <cstring>void read_grid_info(string code)
{char filepath[100] = {0};sprintf(filepath, "%s", "../grid/");strcat(filepath, code.c_str());size_t diff = strlen(code.c_str()) - code.size();if (diff > 0) {filepath[strlen(filepath) - diff] = 0;}strcat(filepath, ".csv");cout << filepath << endl;}int main()
{string testcode = "601998.SH";read_grid_info(testcode);return 0;
}

输出结果

../grid/601998.SH.csv

⑥substr说明

  • 形式 : s.substr(pos, len)
  • 返回值: string,包含s中从pos开始的len个字符的拷贝(pos的默认值是0,len的默认值是s.size() - pos,即不加参数会默认拷贝整个s)
  • 异常 :若pos的值超过了string的大小,则substr函数会抛出一个out_of_range异常;若pos+n的值超过了string的大小,则substr会调整n的值,只拷贝到string的末尾

⑦replace替换

需求:把小写wbm===>WBM

#include <iostream>
#include <string>using namespace std;int main()
{string s1 = "wbm hello wbm 111  wbm 222  wbm 333 ";// 把小写wbm===>WBMsize_t offindex = s1.find("wbm", 0);while (offindex != string::npos){cout << "offindex:" << offindex << endl;// 从offindex位置起的3个字符替换为"WBM"s1.replace(offindex, 3, "WBM");offindex = offindex + 3;offindex = s1.find("wbm", offindex); }cout << s1 << endl;// WBM hello WBM 111  WBM 222  WBM 333return 0;}

⑧erase删除

需求:将字符串中的hello全部删除

#include <iostream>
#include <string>using namespace std;int main()
{string s1 = "hello world, hello string";// 将string中的hello全部删除string part = "hello";size_t i = s1.find(part, 0);while (i != std::string::npos){s1.erase(i, part.size());i = s1.find(part, 0);cout << "(" << s1 << ")" << endl;}// ( world, hello string)// ( world,  string)cout << "(" << s1 << ")" << endl;  // ( world,  string)return 0;}

⑨insert插入

需求:在字符串指定位置插入新的子串

#include <iostream>
#include <string>using namespace std;int main()
{string s2 = "BBB";// 在位置0处插入数据s2.insert(0, "AAA"); cout << s2 << endl; // AAABBB// 在末尾插入数据s2.insert(s2.size(), "CCC");cout << s2 << endl;  // AAABBBCCCreturn 0;}

(5)牛刀小试

1.仅仅反转字母

力扣题目:917. 仅仅反转字母 - 力扣(LeetCode)

class Solution {
public:string reverseOnlyLetters(string s) {size_t left = 0 , right = s.size() - 1;while(left < right){while(left < right && !isalpha(s[left])){left++;}while(left < right && !isalpha(s[right])){right--;}if(left < right){swap(s[left] , s[right]);right--;left++;}}return s;}
};

2.字符串中的第一个唯一字符

力扣题目:387. 字符串中的第一个唯一字符 - 力扣(LeetCode)

class Solution {
public:int firstUniqChar(string s) {int count[26] = { 0 };for(int i = 0; i < s.size() ; i++){count[s[i] - 'a']++;}for(int i = 0; i < s.size() ; i++){if(count[s[i] - 'a'] == 1)return i;}return -1;}
};

3.字符串最后一个单词的长度

牛客题目:字符串最后一个单词的长度_牛客题霸_牛客网

#include<iostream>
#include<string>
using namespace std;
int main()
{string s;getline(cin, s);size_t pos = s.rfind(' ');cout << s.size() - pos - 1 << endl;return 0;
}

4.验证回文串

力扣题目:125. 验证回文串 - 力扣(LeetCode)

class Solution {
public:bool isLetterOrNumber(char ch){return (ch >= '0' && ch <= '9')|| (ch >= 'a' && ch <= 'z')|| (ch >= 'A' && ch <= 'Z');}bool isPalindrome(string s) {// 先将小写字母转换成大写,再判断for(auto& ch : s){if(ch >= 'a' && ch <= 'z')ch -= 32;}int begin = 0, end = s.size() - 1;while(begin < end){while(begin < end && !isLetterOrNumber(s[begin]))begin++;while(begin < end && !isLetterOrNumber(s[end]))end--;if(s[begin] != s[end])return false;else{begin++;end--;}}return true;}
};

5.整数字符串相加

力扣题目:415. 字符串相加 - 力扣(LeetCode)

class Solution {
public:string addStrings(string num1, string num2) {int end1 = num1.size() - 1;int end2 = num2.size() - 1;int value1 = 0, value2 = 0, next = 0;string addret; // 用来接收相加后的值while(end1 >= 0 || end2 >= 0){if(end1 >= 0)value1 = num1[end1--] - '0';elsevalue1 = 0;if(end2 >= 0)value2 = num2[end2--] - '0';elsevalue2 = 0;int valueret = value1 + value2 + next;if(valueret >= 10){valueret -= 10;next = 1;}elsenext = 0;addret += valueret + '0';}if(next == 1){addret += '1';}reverse(addret.begin(),addret.end());return addret;}
};

(6)c++中string的assign方法使用

①assign的声明

string的实际.h和.cpp文件是basic_string.h 和basic_string.tcc,所以string中assign也在这两个文件声明和定义;

basic_string& assign(const basic_string& __str)
basic_string& assign(basic_string&& __str)
basic_string& assign(const basic_string& __str, size_type __pos, size_type __n)
basic_string& assign(const _CharT* __s, size_type __n)
basic_string& assign(const _CharT* __s)
basic_string& assign(size_type __n, _CharT __c)
basic_string& assign(_InputIterator __first, _InputIterator __last)
basic_string& assign(initializer_list<_CharT> __l) 

②assign是赋值运算符

其实string的赋值运算符basic_string& operator=(const basic_string& __str)就是调用了assign方法。赋值运算符就是简单的包装了assign方法:

basic_string&
operator=(const basic_string& __str)
{ return this->assign(__str); }

其中:basic_string& assign(const basic_string& __str)的定义:

basic_string&
assign(const basic_string& __str)
{this->_M_assign(__str);return *this;
}

所以:

string s1;
string s2;
s1=s2;
s1.assign(s2); //是等效的

具体用法:

  • string &operator=(const string &s); //把字符串s赋给当前的字符串
  • string &assign(const char *s); //把字符串s赋给当前的字符串
  • string &assign(const char *s, int n); //把字符串s的前n个字符赋给当前的字符串
  • string &assign(const string &s);  //把字符串s赋给当前字符串
  • string &assign(int n,char c);  //用n个字符c赋给当前字符串
  • string &assign(const string &s,int start, int n);  //把字符串s中从start开始的n个字符赋给当前字符串

③例子

#include <iostream>
#include <string>
using std::string;int main()
{string s1;                  // 默认初始化,s1是一个空的字符串string s6(4, '6');          // 初始化n个字符'6‘串成的字符串s1.assign(s6);              // 将s6赋值给s1return 0;
}

(7)string常用算法

#include <iostream>
#include <string>
#include <algorithm>  // STL算法对应的头文件using namespace std;// string算法相关
int main()
{// 1.查找数据string s1 = "hello world";string::iterator it = find(s1.begin(), s1.end(), 'h');if ( it != s1.end()){// 打印对应的字符cout << *it << endl;  // h}// 2.删除数据string s2 = "hello world";// 将s2全部删除s2.erase(s2.begin(), s2.end());cout << s2.size() << endl;  // 0string s3 = "hello world";// 将s3中的l全部删除string::iterator m_it = find(s3.begin(), s3.end(), 'l');while ( m_it != s3.end() ){s3.erase(m_it, m_it+1);m_it = find(s3.begin(), s3.end(), 'l');cout << "[" << s3 << "]" << endl;}// [helo world]// [heo world]// [heo word]string s4 = "my new book name is your new book name";// 将s4中的name全部删除string part = "name";m_it = find(s4.begin(), s4.end(), part[0]);while (m_it != s4.end()){// cout << *m_it << endl;bool is_find = true;for (int i = 0; i < part.size(); i++){string::iterator temp = m_it + i;if (*temp != part[i]){is_find = false;}}if (is_find){s4.erase(m_it, m_it+part.size());cout << "[" << s4 << "]" << endl;}m_it++;m_it = find(m_it, s4.end(), part[0]);}// [my new book  is your new book name]// [my new book  is your new book ]// 3.使用transform和toupper进行大小写转化// toupper, tolowerstring s5 = "AAAbbb";// transform(s5.begin(), s5.end(), s5.begin(), toupper);// 报错no matching function for call to 'transform(std::__cxx11::basic_string<char>// 错误原因:既有C版本的toupper/tolower函数,又有STL模板函数toupper/tolower,二者存在冲突// 解决办法:在toupper/tolower前面加::,强制指定是C版本的transform(s5.begin(), s5.end(), s5.begin(), ::toupper);cout << s5 << endl;  // AAABBBtransform(s5.begin(), s5.end(), s5.begin(), ::tolower);cout << s5 << endl;  // aaabbbreturn 0;}

(8)相关工具函数

去掉两端空格

#include <iostream>
#include <string>std::string remove_left_right_space(std::string src)
{int is_all_space = 1;for (size_t i = 0; i < src.size(); i++){if (src.substr(i, 1) != " "){is_all_space = 0;}}if (is_all_space == 1){return "";}std::string dst = src;size_t index;// deal leftstd::string dst2 = dst;if (dst.substr(0, 1) == " "){size_t start;for (size_t i = 0; i < dst.size(); i++){if (dst.substr(i, 1) == " "){start = i;}else{break;}  }dst2 = dst.substr(start+1);}// deal rightstd::string dst3 = dst2;if (dst2.substr(dst2.size()-1, 1) == " "){size_t end;for (size_t i = dst2.size() - 1; i >= 0; i--){if (dst2.substr(i, 1) == " "){end = i;}else{break;}  }dst3 = dst2.substr(0, end);}return dst3;
}int main()
{std::string src = "     hello world  ";src = remove_left_right_space(src);std::cout << "(" << src << ")" << std::endl;  // (hello world)
}

获取子串出现的次数

#include <iostream>
#include <string>using namespace std;size_t CountSubstr(const string &data, const string &substr)
{// 函数作用:获取data中substr的出现次数int index = data.find(substr, 0);size_t ret = 0;while (index != string::npos) {// cout << index << endl;ret++;index++;index = data.find(substr, index);}return ret;
}int main()
{string s1 = "wbm hello wbm 111  wbm 222  wbm 333 ";// 需求:查找wbm的出现次数cout << CountSubstr(s1, "wbm") << endl;return 0;}


end


http://www.hkcw.cn/article/lNExqvbBuB.shtml

相关文章

Python基于局部线性嵌入法和多维缩放方法的S形流行数据降维对比项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档&#xff09;&#xff0c;如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在现代数据分析领域&#xff0c;面对高维数据的挑战日益增加&#xff0c;降维技术成为理解和处理复杂数据集的关键工…

ABP-Book Store Application中文讲解 - Part 5: Authorization

ABP-Book Store Application中文讲解 - Part 5: Authorization 1. 汇总 ABP-Book Store Application中文讲解-汇总-CSDN博客 2. 前一章 ABP-Book Store Application中文讲解 - Part 4: Integration Tests-CSDN博客 项目之间的引用关系。 ​ ABP有一套完整的权限控制系统&…

安全月报 | 傲盾DDoS攻击防御2025年5月简报

引言 在2025年5月&#xff0c;全球数字化进程高歌猛进&#xff0c;各行各业深度融入数字浪潮&#xff0c;人工智能、物联网、大数据等前沿技术蓬勃发展&#xff0c;进一步夯实了数字经济的基石。然而&#xff0c;在这看似繁荣的数字生态背后&#xff0c;网络安全威胁正以惊人的…

rabbitMQ初入门

1、MQ定义及作用 MQ即MessageQueue&#xff0c;消息队列。其中消息Message&#xff1a;在不同的应用中传递的数据&#xff1b;队列Queue&#xff1a;一种FIFO先进先出的数据结构。将消息以队列的形式存储起来&#xff0c;并且在不同的应用程序之间进行传递&#xff0c;这就成了…

重新审视自回归语言模型的知识蒸馏

Revisiting Knowledge Distillation for Autoregressive Language Models 发表&#xff1a;ACL 2024 机构&#xff1a;School of Computer Science Abstract 知识蒸馏&#xff08;Knowledge Distillation, KD&#xff09;是一种常见的方法&#xff0c;用于压缩教师模型&…

力扣 88.合并两个有序数组

文章目录 题目介绍题解 题目介绍 题解 法一&#xff1a;暴力法 class Solution {public void merge(int[] nums1, int m, int[] nums2, int n) {for(int i 0; i < n; i){nums1[mi] nums2[i];}Arrays.sort(nums1);} }法二&#xff1a;倒序双指针 时间复杂度为O(mn) 从右…

生成模型+两种机器学习范式

生成模型&#xff1a;从数据分布到样本创造 生成模型&#xff08;Generative Model&#xff09; 是机器学习中一类能够学习数据整体概率分布&#xff0c;并生成新样本的模型。其核心目标是建模输入数据 x 和标签 y 的联合概率分布 P(x,y)&#xff0c;即回答 “数据是如何产生的…

Python趣学篇:Turtle绘制炫酷彩色螺旋图案

名人说&#xff1a;路漫漫其修远兮&#xff0c;吾将上下而求索。—— 屈原《离骚》 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 专栏介绍&#xff1a;《Python星球日记》 目录 一、螺旋之美&#xff1a;当数学遇上艺…

学习threejs,交互式神经网络可视化

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.EffectComposer 后期…

50天50个小项目 (Vue3 + Tailwindcss V4) ✨ | Dad Jokes(冷笑话卡片)

&#x1f4c5; 我们继续 50 个小项目挑战&#xff01;—— DadJokes 组件 仓库地址&#xff1a;https://github.com/SunACong/50-vue-projects 项目预览地址&#xff1a;https://50-vue-projects.vercel.app/ 豆包翻译确实可以&#xff0c;冷笑话应该属于各类语言比较难理解的…

ESP32开发之LED闪烁和呼吸的实现

硬件电路介绍GPIO输出模式GPIO配置过程闪烁灯的源码LED PWM的控制器(LEDC)概述LEDC配置过程及现象整体流程 硬件电路介绍 电路图如下&#xff1a; 只要有硬件基础的应该都知道上图中&#xff0c;当GPIO4的输出电平为高时&#xff0c;LED灯亮&#xff0c;反之则熄灭。如果每间…

【办公类-48-04】202506每月电子屏台账汇总成docx-5(问卷星下载5月范围内容,自动获取excel文件名,并转移处理)

背景需求&#xff1a; 1-4月电子屏表格&#xff0c;都是用这个代码将EXCEL数据整理成分类成3个WORD表格。 【办公类-48-04】20250118每月电子屏台账汇总成docx-4&#xff08;提取EXCLE里面1月份的内容&#xff0c;自制月份文件夹&#xff09;-CSDN博客文章浏览阅读1.2k次&…

25年宁德时代新能源科技SHL 测评语言理解数字推理Verify题库

宁德时代新能源科技的SHL测评中&#xff0c;语言理解部分主要考察阅读理解、逻辑填空和语句排序等题型&#xff0c;要求应聘者在17分钟内完成30题。阅读理解需要快速捕捉文章主旨和理解细节信息&#xff1b;逻辑填空则要根据语句逻辑填入最合适的词汇&#xff1b;语句排序是将打…

Windows下WSL(Ubuntu)安装1Panel

1Panel 1Panel 提供了一个直观的 Web 界面和 MCP Server&#xff0c;帮助用户轻松管理 Linux 服务器中的网站、文件、容器、数据库以及大型语言模型&#xff08;LLMs&#xff09;。 官网地址&#xff1a;1Panel - 现代化、开源的 Linux 服务器运维管理面板 - 官网 前置条件 …

virtualbox安装扩展工具以支持共享文件夹

1.下载扩展镜像 https://download.virtualbox.org/virtualbox/7.0.16/ 2.加载扩展镜像并安装 3. 配置共享文件夹

实现仿中国婚博会微信小程序

主要功能&#xff1a; 1、完成底部标签导航设计、首页海报轮播效果设计和宫格导航设计&#xff0c;如图1所示 2、在首页里&#xff0c;单击全部分类宫格导航的时候&#xff0c;会进入到全部分类导航界面&#xff0c;把婚博会相关内容的导航集成到一个界面里&#xff0c;如图2…

Meta ASC广告:智能电商营销利器解析

Meta推出的ASC广告&#xff08;全称Advantage Shopping Campaign&#xff09;是专为电商卖家打造的智能营销利器。作为新一代自动化购物广告解决方案&#xff0c;它通过AI技术重塑了传统广告投放模式&#xff0c;为商家带来更高效的转化路径。 五大核心优势解析&#xff1a; 全…

1.1Nodejs和浏览器中的二进制处理

Buffer 在 Node.js 中&#xff0c;Buffer 类用于处理二进制数据。由于 JavaScript 在浏览器环境中主要用于处理字符串和数字等类型的数据&#xff0c;对二进制数据的处理能力较弱&#xff0c;因此 Node.js 引入了 Buffer 类来弥补这一不足&#xff0c;特别是在处理文件系统操作…

redis的哨兵模式和Redis cluster

目录 一. redis的主从复制 二. 哨兵模式 2.1 定义 2.2 作用 2.3 配置实例 三. Redis cluster 3.1 定义 3.2 作用 3.3 配置实例 1. 新建集群文件目录 2. 准备可执行文件到每个文件夹 3. 开启群集功能 4. 启动redis节点 5. 查看是否启动成功 6. 启动集群 7. 测试…

[Java 基础]打印金字塔

实现一个 Java 程序&#xff0c;让用户输入金字塔的层数&#xff0c;打印出对应层数的金字塔。 比如&#xff0c;如果用户指定金字塔的层数是 5&#xff0c;那么将会打印如下的金字塔&#xff1a; 0000* 000*** 00***** 0******* 假如 i 代表的是行&#xff0c;i 从 1 开始…