【编码艺术:掌握String类函数接口的妙用指南】(三)

简介: 【编码艺术:掌握String类函数接口的妙用指南】

【编码艺术:掌握String类函数接口的妙用指南】(二):https://developer.aliyun.com/article/1425650


5.6.clear()只是将string中有效字符清空,不改变底层空间大小。



6. string类对象的增删查改操作



6.1.增加


       在string尾部追加字符时,s.push_back(c) / s.append(1, c) / s += 'c'三种的实现方式差不多,一般情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串。


这里有一个问题:string s1 = "hello world";//这个可行吗?可行,这里是一个单参数的构造函数,它会隐式类型转换,它先去构造,然后再拷贝构造,不过这里编译器可能会优化成直接构造。


我们来看一下append的使用。

int main()
{
  std::string str;
  std::string str2 = "Writing ";
  std::string str3 = "print 10 and then 5 more";
  // used in the same order as described above:
  str.append(str2);                       // "Writing "
  str.append(str3, 6, 3);                   // "10 "
    str.append("here: ");                   // "here: "
  str.append("dots are cool", 5);          // "dots "
  str.append(10u, '.');                    // ".........."
  str.append(str3.begin() + 8, str3.end());  // " and then 5 more"
  std::cout << str << '\n';
  return 0;
}


我们上面有了尾插,那我们有没有头插呢?或者在中间插入呢?

// inserting into a string
#include <iostream>
#include <string>
int main ()
{
  std::string str="to be question";
  std::string str2="the ";
  std::string str3="or not to be";
  std::string::iterator it;
  // used in the same order as described above:
  str.insert(6,str2);                 // to be (the )question
  str.insert(6,str3,3,4);             // to be (not )the question
  str.insert(10,"that is cool",8);    // to be not (that is )the question
  str.insert(10,"to be ");            // to be not (to be )that is the question
  str.insert(15,1,':');               // to be not to be(:) that is the question
  it = str.insert(str.begin()+5,','); // to be(,) not to be: that is the question
  str.insert (str.end(),3,'.');       // to be, not to be: that is the question(...)
  str.insert (it+2,str3.begin(),str3.begin()+3); // (or )
  std::cout << str << '\n';
  return 0;
}


实际中头插使用较少,因为要挪动数据,效率不高。那删除字符呢?


6.2.删除


// string::erase
#include <iostream>
#include <string>
int main ()
{
  std::string str ("This is an example sentence.");
  std::cout << str << '\n';
                                           // "This is an example sentence."
  str.erase (10,8);                        //            ^^^^^^^^
  std::cout << str << '\n';
                                           // "This is an sentence."
  str.erase (str.begin()+9);               //           ^
  std::cout << str << '\n';
                                           // "This is a sentence."
  str.erase (str.begin()+5, str.end()-9);  //       ^^^^^
  std::cout << str << '\n';
                                           // "This sentence."
  return 0;
}


6.3.查找


注意:

  • pos含义:搜索字符串中要查找的第一个字符的位置。
  • 函数返回值:第一个匹配项的第一个字符的位置。 如果未找到任何匹配项,则该函数返回 string::npos

// string::find
#include <iostream>       // std::cout
#include <string>         // std::string
int main ()
{
  std::string str ("There are two needles in this haystack with needles.");
  std::string str2 ("needle");
  // different member versions of find in the same order as above:
  std::size_t found = str.find(str2);
  if (found!=std::string::npos)
    std::cout << "first 'needle' found at: " << found << '\n';
  found=str.find("needles are small",found+1,6);
  if (found!=std::string::npos)
    std::cout << "second 'needle' found at: " << found << '\n';
  found=str.find("haystack");
  if (found!=std::string::npos)
    std::cout << "'haystack' also found at: " << found << '\n';
  found=str.find('.');
  if (found!=std::string::npos)
    std::cout << "Period found at: " << found << '\n';
  // let's replace the first needle:
  str.replace(str.find(str2),str2.length(),"preposition");
  std::cout << str << '\n';
  return 0;
}


现在我们来使用一下find,查找字符串的后缀是什么?这里我们会使用到substr。

int main()
{
  string s1("Test.cpp");
  string s2("Test.tar.zip");
  size_t pos1 = s1.find('.');
  if(pos1 != string::npos)
  {
    string suff1 = s1.substr(pos1, s1.size() - pos1);
    cout << suff1 << endl;//.cpp
    string suff2 = s1.substr(pos1);//默认取到结尾
    cout << suff2 << endl;//.cpp
  }
  size_t pos2 = s2.find('.');
  if (pos2 != string::npos)
  {
    string suff1 = s2.substr(pos2, s2.size() - pos2);
    cout << suff1 << endl;//.tar.zip
    string suff2 = s2.substr(pos2);//默认取到结尾
    cout << suff2 << endl;//.tar.zip
  }
  //搜索字符串中由参数指定的序列的最后一次出现
  size_t pos3 = s2.rfind('.');
  if (pos2 != string::npos)
  {
    string suff1 = s2.substr(pos3, s2.size() - pos3);
    cout << suff1 << endl;//.zip
    string suff2 = s2.substr(pos3);//默认取到结尾
    cout << suff2 << endl;//.zip
  }
  return 0;
}


运行结果:


如何将一个网址分开呢?

#include <iostream>
#include <string>
using namespace std;
int main()
{
  string str("https://cplusplus.com/reference/string/string/substr/");
  string sub1, sub2, sub3;
  size_t pos1 = str.find(':');
  //左闭右开区间
  sub1 = str.substr(0, pos1 - 0);
  cout << sub1 << endl;
  size_t pos2 = str.find('/', pos1 + 3);
  sub2 = str.substr(pos1 + 3, pos2 - (pos1 + 3));
  cout << sub2 << endl;
  sub3 = str.substr(pos2 + 1);
  cout << sub3 << endl;
  return 0;
}


运行结果:


6.4.修改


// replacing in a string
#include <iostream>
#include <string>
int main ()
{
  std::string base="this is a test string.";
  std::string str2="n example";
  std::string str3="sample phrase";
  std::string str4="useful.";
  // replace signatures used in the same order as described above:
  // Using positions:                 0123456789*123456789*12345
  std::string str=base;           // "this is a test string."
  str.replace(9,5,str2);          // "this is an example string." (1)
  str.replace(19,6,str3,7,6);     // "this is an example phrase." (2)
  str.replace(8,10,"just a");     // "this is just a phrase."     (3)
  str.replace(8,6,"a shorty",7);  // "this is a short phrase."    (4)
  str.replace(22,1,3,'!');        // "this is a short phrase!!!"  (5)
  // Using iterators:                                               0123456789*123456789*
  str.replace(str.begin(),str.end()-3,str3);                    // "sample phrase!!!"      (1)
  str.replace(str.begin(),str.begin()+6,"replace");             // "replace phrase!!!"     (3)
  str.replace(str.begin()+8,str.begin()+14,"is coolness",7);    // "replace is cool!!!"    (4)
  str.replace(str.begin()+12,str.end()-4,4,'o');                // "replace is cooool!!!"  (5)
  str.replace(str.begin()+11,str.end(),str4.begin(),str4.end());// "replace is useful."    (6)
  std::cout << str << '\n';
  return 0;
}


根据上面的查找和修改可以轻松解决一个我们曾经遇到的问题,将日期"2023-11-23"中的'-'修改为'/'。

int main()
{
  string str("2023-11-23");
  cout << str << endl;
  size_t pos = str.find('-');
  // '-'修改为'/'
  while (pos != string::npos)
  {
    str.replace(pos, 1, 1, '/');
    pos = str.find('-');
  }
  cout << str << endl;
  return 0;
}


我们看一下我们的代码有什么问题没?我们发现我们每次找'-'都是从字符串的其实位置开始找,那么这也效率比较低,其实我们第一找到'-'后,得到第一次出现'-'的位置,后面再找'-'就可以从上次找的位置+1即可,这样效率就提高很多,但是replace的效率比较低,我们下面替换一个字符还好,但是如果替换成'///'时,此时就要往后挪动数据才能插入,这样效率比较低,所以replace我们能少用尽量就少用。

int main()
{
  string str("2023-11-23");
  cout << str << endl;
  size_t pos = str.find('-', 0);
  // '-'修改为'/'
  if (pos != string::npos)
  {
    str.replace(pos, 1, 1, '/');
    pos = str.find('-', pos + 1);
  }
  cout << str << endl;
  return 0;
}

所以这里我们有更好的方法,使用范围for+赋值。

int main()
{
  string str("2023-11-23");
  cout << str << endl;
  string str1;
  for (auto ch : str)
  {
    if (ch == '-')
      str1 += '/';
    else
      str1 += ch;
  }
  cout << str1 << endl;
    str.swap(str1);
  return 0;
}


运行结果:


这里有一个细节问题:我们上面使用的是C++ 标准库中 std::string 类的成员函数。


string::swap 是 C++ 标准库中 std::string 类的成员函数,用于交换两个字符串的内容。它是在字符串对象上调用的函数,例如:

std::string str1 = "Hello";
std::string str2 = "World";
str1.swap(str2); // 交换 str1 和 str2 的内容


swap 是一个通用的 C++ 函数,用于交换两个对象的值。对于字符串来说,可以使用 std::swap 或直接使用 swap 来交换两个字符串的内容,例如:

std::string str1 = "Hello";
std::string str2 = "World";
std::swap(str1, str2); // 交换 str1 和 str2 的内容
// 或者直接使用 swap
swap(str1, str2);


主要区别在于调用方式和命名空间。string::swap 是 std::string 类的成员函数,而 swap 是一个通用的函数,可以在合适的作用域下直接使用或通过 std::swap 来调用。两者都可以用于交换字符串的内容。同时std::swap 参数是函数模板,使用的时候实例化,需要拷贝,消耗较大,而string::swap 是直接交换两个字符串的地址,后面实现string类的时候可以看到。


【编码艺术:掌握String类函数接口的妙用指南】(四):https://developer.aliyun.com/article/1425656

相关文章
|
29天前
|
存储 C++ 容器
C++入门指南:string类文档详细解析(非常经典,建议收藏)
C++入门指南:string类文档详细解析(非常经典,建议收藏)
38 0
|
7天前
|
存储 安全 C语言
【C++】string类
【C++】string类
|
存储 编译器 Linux
标准库中的string类(中)+仅仅反转字母+字符串中的第一个唯一字符+字符串相加——“C++”“Leetcode每日一题”
标准库中的string类(中)+仅仅反转字母+字符串中的第一个唯一字符+字符串相加——“C++”“Leetcode每日一题”
|
9天前
|
编译器 C++
标准库中的string类(上)——“C++”
标准库中的string类(上)——“C++”
|
20天前
|
存储 算法 C语言
【C++初阶】8. STL初阶 + String类
【C++初阶】8. STL初阶 + String类
48 1
|
20天前
|
C语言 C++
【C++初阶】9. string类的模拟实现
【C++初阶】9. string类的模拟实现
38 1
|
1月前
|
存储 编译器 C++
string类的模拟实现
string类的模拟实现
29 0
|
1月前
|
编译器 Linux C++
string类的函数讲解
string类的函数讲解
15 1
|
1月前
|
存储 缓存 编译器
C++:String类的使用
C++:String类的使用
|
1月前
|
Java 索引
【Java】String类常用方法总结
【Java】String类常用方法总结
20 0