C++STL标准库学习笔记(八)string

前言:

  从这里开始,就是郭炜老师的《程序设计与算法(三)C++面向对象程序设计》的内容了,笔记会更加具体,会有很多类与对象的内容,同时和之前的笔记一样更加偏向实际运用方面而不是纯理论。

  在这个笔记中,我把大多数代码都加了注释,我的一些想法和注解用蓝色字体标记了出来,重点和需要关注的地方用红色字体标记了出来。

  另外,由于笔者主要是在word上编辑的这篇文章,除了代码部分的部分””双引号不是编辑器可以理解的双引号,所以如果要复制的话记得修改双引号,造成不便深表歉意。

  在这一篇文章中,我们主要介绍string的用法和应用

1.1 string的建立

  string类是模板类:

    typedef basic_string<char>string;

  使用string类要包含头文件<string>

  string对象的初始化:

  string s1(hello);

  string month = March;

  string s2(8,x);(这里面s2就有8个x)

  错误的初始化方法:

  string error1 = ‘c’; //错

  string error2(‘u’); //错

  string error3 = 22; //错

  string error4(8); //错

  (归纳起来就是不能直接赋字符和其他类型的变量)

  但是我们可以将字符赋给string对象

  string s;

  s = ‘n’;

  这样是对的

  一个包含以上的内容的简单样例:

C++STL标准库学习笔记(八)string
 1 #include<iostream>
 2 #include<string>
 3 using namespace std;
 4 
 5 int main(int argc, char const *argv[])
 6 {
 7     string s1("hello");
 8     cout<<s1<<endl;//输出:hello
 9     string s2(8,'x');
10     cout<<s2<<endl;//输出:xxxxxxxx
11     string month = "March";
12     cout<<month<<endl;//输出:March
13     string s;
14     s = 'n';
15     cout<<s<<endl;//输出:n
16     return 0;
17 }
样例

  string对象的长度用成员函数length()读取

  string s(“hello”);

  cout<<s.length()<<endl;

  string支持流读取运算符(如果没学过类中的输入输出流的话,只用了解它支持cin就行了)

  string stringObject;

  cin>>stringObject;

  string支持getline函数

  string s;

  getline(cin,s);(getline相当于读取一整行的cin,不会因为空格而停顿,在输入人名时会有用,比如用cin输入Awake Fantasy就会在接收完Awake时就结束了,而getline就能接收整个名字)

1.2 string的赋值和连接

  用 = 赋值

  string s1(“cat”),s2;

  s2 = s1;

  用assign成员函数复制

  string s1(“cat”),s3;

  s3.assign(s1);

  用assign成员函数部分复制

  string s1(“catpig”),s3;

  s3.assign(s1,1,3);//从s1中下标为1的字符开始复制三个字符

  (测试一下发现这里s3是atp,看来string是从下标为1开始存的,我还以为老师会复制cat呢)

  单个字符复制

  s2[5] = s1[3] =’a’;

  逐个访问string对象中的字符

  string s1(“hello”);

  for(int i = 0;i<s1.length();i++)

    cout<<s1.at(i)<<endl;

  成员函数at会做范围检查,如果超出范围,会抛出out_of_range异常,而下标运算符[]不做范围检查。(不做范围检查的效率比做的快,所以要是打比赛要用什么懂得都懂)

  用 + 运算符连接字符串

  string s1(“good ”),s2(“morning!”);

  s1 += s2;

  cout<< s1;

  用成员函数append连接字符串

  string s1(“good ”),s2(“morning!”);

  s1.append(s2);

  cout<<s1;

  s2.append(s1,3,s1.size());//s1.size()为s1的字符数

  cout<<s2;

  下标为3开始,s1.size()个字符,如果字符串内没有足够字符,则复制到字符串最后一个字符

1.3 比较string

  用关系运算符比较string的大小

  ==, >, >=, <, <=, !=

  返回值都是bool类型,成立返回true,否则返回false

  例如:

1     string s1("hello"),s2("hello"),s3("hell");
2     bool b = (s1 == s2);
3     cout<<b<<endl;
4     b = (s1 == s3);
5     cout<<b<<endl;
6     b = (s1 > s3);
7     cout<<b<<endl;

  输出:1 0 1

  用成员函数compare比较string的大小

 1     string s1("hello"),s2("hello"),s3("hell");
 2     int f1 = s1.compare(s2);
 3     int f2 = s1.compare(s3);
 4     int f3 = s3.compare(s1);
 5     int f4 = s1.compare(1,2,s3,0,3);//s1 1-2; s3 0-3
 6     int f5 = s1.compare(0,s1.size(),s3);//s1 0-end
 7     cout<<f1<<endl;//0  hello == hello
 8     cout<<f2<<endl;//1  hello > hell
 9     cout<<f3<<endl;//-1 hell < hello
10     cout<<f4<<endl;//-1 el < hell
11     cout<<f5<<endl;//1  hello > hell

(int f4 = s1.compare(1,2,s3,0,3);//s1 1-2; s3 0-3

这里的1,2是表示从1开始的2个字符,不是下标1到下标2,有兴趣可以去尝试一下)

1.4 子串

  成员函数 substr

1     string s1("hello world"),s2;
2     s2 = s1.substr(4,5);
3     cout<<s2<<endl;//结果:o wor

  这里substr(4,5)是指下标4开始5个字符

  成员函数 swap

1     string s1("hello world"),s2("really");
2     s1.swap(s2);
3     cout<<s1<<endl;//结果:really
4     cout<<s2<<endl;//结果:hello world

  寻找string中的字符

  成员函数 find()

  string s1(“hello world”);

  s1.find(“lo”);

  在s1中从前向后查找”lo”第一次出现的地方,如果找到,返回”lo”开始的位置,即l所在位置的下标。如果找不到,返回string::npos(string中定义的静态常量)(npos应该就是 no position吧)

  成员函数rfind()

  string s1(“hello world”);

  s1.rfind(“lo”);

  在s1中从后向前查找”lo”第一次出现的地方,如果找到,返回”lo”开始的位置,即l所在位置的下标。如果找不到,返回string::npos(string中定义的静态常量)(这个rfind的“r”应该就是reverse)

  find还可以指定开始查找的位置:

1     string s1("hello worlld");
2     cout<<s1.find("ll",1)<<endl;//结果:2
3     cout<<s1.find("ll",2)<<endl;//结果:2
4     cout<<s1.find("ll",3)<<endl;//结果:9
5     //分别从下标1,2,3开始查找“ll”

  (注意一下哈,从第三个开始找时,这里s1是“worlld”,有两个‘l’,所以找到了,如果是“world”,输出的是垃圾数字(18446744073709551615),如果自己测试一下的话,会发现find函数找不到的返回值是前面的提到的string::npos)

  成员函数find_first_of()

  string s1("hello world");

  s1.find_first_of("abcd");

  在s1中从前向后查找"abcd"中任何一个字符第一次出现的地方,如果找到,返回找到字母的位置,如果找不到,返回string::npos。

  成员函数find_last_of()

  string s1("hello world");

  s1.find_last_of("abcd");

  在s1中查找"abcd"中任何一个字符最后一次出现的地方,如果找到,返回找到字母的位置,如果找不到,返回string::npos。

  成员函数find_first_not_of()

  string s1("hello world");

  s1.find_first_not_of("abcd");

  在s1中从前向后查找不在"abcd"中的字母第一次出现的地方,如果找到,返回找到字母的位置,如果找不到,返回string::npos。

  成员函数find_last_not_of()

  string s1("hello world");

  s1.find_last_not_of("abcd");

  在s1中从后向前查找不在"abcd"中的字母第一次出现的地方,如果找到,返回找到字母的位置,如果找不到,返回string::npos。

  上述4个函数的例子:

 1     string s1("hello world");
 2     cout<<s1.find("ll")<<endl;//结果:2
 3     cout<<s1.find("abc")<<endl;//结果:18446744073709551615
 4     cout<<s1.rfind("ll")<<endl;//结果:2
 5     cout<<s1.rfind("abc")<<endl;//结果:18446744073709551615
 6     cout<<s1.find("ll")<<endl;//结果:2
 7     cout<<s1.find_first_of("abcde")<<endl;//结果:1
 8     cout<<s1.find_first_of("abc")<<endl;//结果:18446744073709551615
 9     cout<<s1.find_last_of("abcde")<<endl;//结果:10
10     cout<<s1.find_last_of("abc")<<endl;//结果:18446744073709551615
11     cout<<s1.find_first_not_of("abcde")<<endl;//结果:0
12     cout<<s1.find_first_not_of("abc")<<endl;//结果:0
13     cout<<s1.find_last_not_of("abcde")<<endl;//结果:9
14     cout<<s1.find_last_not_of("abc")<<endl;//结果:10

(那串乱七八糟的数字就是npos对应的)

1.5 删除string中的字符

  成员函数erase()

  string s1("hello world");

  s1.erase(5);

  cout<<s1;

  cout<<s1.length();

  cout<<s1.size();

  去掉下标5及以后的字符

  输出:hello55

  (刚查了一下,size()和length()完全等同,只是length的可读性比较好而已)

1.6 替换string中的字符

  成员函数replace()

  用法1:

  string s1("hello world");

  s1.replace(2,3,"haha");

  cout<<s1;

  将s1中下标2开始的3个字符换成"haha"

  (这里就是把"llo"换成了"haha")

  输出:hehaha world

  用法2:

  string s1("hello world");

  s1.replace(2,3,"haha",1,2);

  cout<<s1;

  将s1中下标2开始的3个字符换成"haha"中下标1开始的2个字符

  (这里就是把"llo"换成了"ha")

  输出:heah world

  (老师这例子真别扭,heha world也行啊,heah是啥玩意啊)

  (我还以为是我英语不好,上网一查:)

  C++STL标准库学习笔记(八)string

 

 

 

  (好吧其实好像有这个单词,但是好像不太正式)

 C++STL标准库学习笔记(八)string

 

 

 

  (啊啊啊不扯了,继续学习)

1.7 在string中插入字符

  成员函数insert()

1     string s1("hello world");
2     string s2("show insert");
3     s1.insert(5,s2);//将s2插入s1下标5的位置
4     cout<<s1<<endl;//输出:helloshow insert world
5     s1.insert(2,s2,5,3);
6     //将s2中下标5开始的3个字符插入s1下标2的位置
7     cout<<s1<<endl;//输出:heinslloshow insert world

  (从这个例子中能发现插入的位置是选定下标的后面)

1.8 转换成C语言式char*字符串

  成员函数c_str()

  string s1("hello world");

  printf("%s\n",s1.c_str());

  s1.c_str()返回传统的const char* 类型字符串,且该字符串以'\0'结尾,

  输出:hello world

  成员函数data()

  string s1("hello world");

  const char * p1 = s1.data();

  for(int i=0;i < s1.length();i++)

    printf("%c",&(p1+i))

  s1.data()返回一个char* (区别)类型的字符串,对s1的修改可能会使p1出错。

  输出:hello world

1.9 字符串流处理

  除了标准流和文件流输入输出外,还可以从string进行输入输出;

  类似istream和ostream进行标准流输入输出,我们用istringstream和ostringstream进行字符串上的输入输出,也称为内存输入输出。

  #include<string>

  #include<iostream>

  #include<sstream>

  样例:

C++STL标准库学习笔记(八)string
 1 #include<iostream>
 2 #include<sstream>
 3 #include<string>
 4 using namespace std;
 5 
 6 int main(int argc, char const *argv[])
 7 {
 8     string input("Input test 123 4.7 A");
 9     istringstream inputString(input);
10     string string1, string2;
11     int i;
12     double d;
13     char c;
14     inputString >> string1 >> string2 >> i >> d >>c;
15     cout<<string1<<endl<<string2<<endl;
16     cout<<i<<endl<<d<<endl<<c<<endl;
17     long L;
18     if (inputString >> L)
19     {
20         cout<<"long\n";
21     }
22     else
23     {
24         cout<<"empty\n";
25     }
26     ostringstream outputString;
27     int a = 10;
28     outputString <<"This "<< a << "ok" << endl;
29     cout<<outputString.str();
30     /*
31     输出:
32     Input
33     test
34     123
35     4.7
36     A
37     empty
38     This 10ok
39     */  
40     return 0;
41 }
样例

  最后inputString >> L 时,因为整个流已经读完了,所以返回false

 

后记:

  开始做这篇笔记是一天前,本来一看视频只有20分钟,想着做完就跑路,然后那天跑路了还没做四分之一,无奈,第二天下午继续,下午2点开始,一动不动做了3个小时才把剩下的做完。

  如果你问我累不累,我可以直接告诉你累,但是我是快乐的,我想说的是如果学习编程没有一个一颗爱好的心,是很难坚持下去的。

  不知为什么,在我思考如何敲程序的时候,我的内心充满的是一种追求答案的渴望,在我敲出程序的时候,我的内心充满的是成就感,在我学习这些知识的时候,我感叹设计STL标准库的那帮人的精巧。

  标准库中太多东西是相似的,不会在这里的函数在另一个地方不兼容,不会存在两个差不多的容器操作方式却截然不同的现象,还有类和对象的设计,提高了巨大的兼容性,或许这就是艺术吧。

  找到自己的爱好和擅长的事物太重要了,如果一个人热爱着一个事物,其他人若在对那件事无感的情况下,热爱者做好那件事的概率相对来说要大得多。而且热爱者还能获得极大的正向反馈。

  所以如果还没有找到自己的方向的话,努力去寻找吧!找到了方向的话,努力去前进吧!

  突发奇想写了这么多,逻辑也是乱七八糟,大家看看就好,如果对大家有所帮助那自然最好,没所帮助的话大家就当我啥也没说吧哈哈哈~~~

上一篇:字符串A->字符串B例题 :最短编辑距离、最优包含 (线性DP)


下一篇:字符串中的变位词 | 循序递进---@二十一画