C++ string使用方法详细介绍

更多关于STL的文章:STL专栏

文章目录

为了防止学习的过程中出现学后忘的情况,我将接触到的知识进行整理,作该笔记,由于本人水平有限,如果出现错误,还望赐正。

介绍

STL(Standard Template Library 标准模板库) 中只有一个字符串类,即 basic_string类 。basic_string 实现管理以 \0 结尾的字符数组,字符类型由模板参数决定。通常,basic_string 被处理为不透明的对象,靠获得只读指针来访问缓冲区,写操作是由 basic_string 的成员函数实现的。

用字符数组存放字符串容易发生数组越界的错误,而且往往难以察觉。因此,C++ 标准模板库设计了 string 数据类型,专门用于字符串处理。string 作为类出现,其集成的操作函数足以完成多数情况下的需要。使用时不必担心内存是否充足、字符串长度等问题。

string 类型的变量就是用来存放字符串的,也叫“string对象”。string 并不是 C++ 的基本数据类型,它是 C++ 标准模板库中的一个“类”。

string成员函数

string 类提供的各种操作函数大致分为八类:构造器和析构器、大小和容量、元素存取、字符串比较、字符串修改、字符串接合、I/O 操作以及搜索和查找 。

函数名称功能
构造函数产生或复制字符串
析构函数销毁字符串
=,assign()赋以新值
swap()交换两个字符串的内容
+=,append(),push_back()添加字符
insert()插入字符
back()返回字符串最后一个字符的引用
front()返回字符串第一个字符的引用
erase(),pop_back()删除字符
clear()清空字符串
resize()改变字符串的长度
shrink_to_fit()请求字符串减小其容量以适合其大小
replace()替换字符串
+拼接字符串
==,! =,<,<=,>,>=,compare()比较字符串内容
size(),length()返回字符串长度
max_size()返回字符的最大可能个数
empty()判断字符串是否为空
capacity()返回重新分配之前的字符容量
reserve()保留内存以存储一定数量的字符
[],at()存/取单一字符
>>,getline()从 stream中读取某值
<<将值写入 stream
copy()将内容复制为一个 C – string
c_str()将内容以 C – string 形式返回
data()将内容以字符数组形式返回
substr()返回子字符串
find()搜寻某子字符串或字符
begin( ),end(),cbegin(),cend()提供正向迭代器支持
rbegin(),rend(),crbegin(),crend()提供逆向迭代器支持
get_allocator()返回配置器
成员类型定义
value_typechar
size_typesize_t
iteratorchar的随机访问迭代器
const_iteratorconst char的随机访问迭代器
pointerchar*
const_pointerconst char*
referencechar&
const_referenceconst char&

成员函数用法示例

1. 构造

构造函数有四个参数,其中三个具有默认值。要初始化一个 string 类,可以使用 C 风格字符串或 string 类型对象,也可以使用 C 风格字符串的部分或 string 类型对象的部分或序列。

注意,不能使用字符或者整数去初始化字符串。//如string str (‘abc’), string str(123) 都是错误的

常见的 string 类构造函数有以下几种形式:

typedef basic_string string;

string var; //生成空字符串
string var(const basic_string& str); //生成字符串str的复制
string var(const basic_string& str, size_type pos); //将字符串str中始于pos的部分作为构造函数的初始值
string var(const basic_string& str, size_type pos, size_type n);
//将字符串str位于区间[pos,pos+n-1]的子字符串作为var的初始值

string var(const char* s); //以C_string类型s作为字符串var的初始值
string var(const char* s, size_type n); //以C_string类型s的前n个字符串作为字符串var的初始值
string var(size_type n, char c);//生成一个字符串,包含n个c字符
string var(InputIterator beg, InputIterator end); //以闭区间[beg, end]内的字符作为字符串var的初始值

析构函数形式如下:

~basic_string() //销毁所有内存,释放内存

【例】

#include<iostream>
#include<string>
using namespace std;

int main()
{ 
    string str ("12345678");
    char ch[ ] = "abcdefgh";

    string str_1(str); //将str全部复制给str_1
    string str_2(str,3);//从字符串str的第3个元素开始,复制后面的所有元素,并赋值给str_2
    string str_3(str, 2, 5); //从字符串str的第2个元素开始,复制5个元素,并赋值给str_3
    string str_4(ch);//复制C_string类型字符串,并赋值给str_4
    string str_5(ch, 5); //将C_string类型字符串ch的前5个元素赋值给str_5
    string str_6(5,'X'); //将5个'X'组成的字符串"XXXXX"赋值给str_6
    string str_7(str.begin(), str.end()); //复制字符串str的所有元素,并赋值给 str_7

    cout << str << endl;
    cout << ch << endl;
    cout << str_1 << endl;
    cout << str_2 << endl;
    cout << str_3 << endl;
    cout << str_4 << endl;
    cout << str_5 << endl;
    cout << str_6 << endl;
    cout << str_7 << endl;
    return 0;
}

以下为程序运行结果:

12345678
abcdefgh

12345678
45678
34567
abcdefgh
abcde
XXXXX
12345678

2. 字符串输入输出

“<<” 和 “>>” 提供了 C++ 语言的字符串输入和字符串输出功能。”<<” 可以将字符读入一个流中(例如 ostream);”>>” 可以实现将以空格或回车为 “结束符” 的字符序列读入到对应的字符串中,并且开头和结尾的空白字符不包括进字符串中。

还有一个常用的 getline() 函数,该函数的原型包括两种形式:

template <class CharType, class Traits, class Allocator > basic_istream<CharType, Traits>& getline (basic_istream<CharType, Traits>& _Istr,basic_string <CharType,Traits, Allocator> &_Str);
//上述原型包含 2 个参数:第 1 个参数是输入流;第 2 个参数是保存输入内容的字符串
template <class CharType, class Traits, class Allocator> basic_istream<CharType, Traits>& getline (basic_istream <CharType, Traits>&_ Istr, basic_string <CharType, Traits, Allocator>& _Str,CharType_Delim);
//上述原型包含 3 个参数:第 1 个参数是输入流,第 2 个参数保存输入的字符串,第 3 个参数指定分界符

该函数可将整行的所有字符读到字符串中。在读取字符时,遇到文件结束符、分界符、回车符时,将终止读入操作,且文件结束符、分界符、回车符在字符串中不会保存;当已读入的字符数目超过字符串所能容纳的最大字符数时,将会终止读入操作。

【例】

#include<iostream>
#include<string>
using namespace std;

int main()
{ 
    //三块代码分开执行
    string str_1;
    cin>>str_1;
    cout<<"第一个:"<< str_1<<endl;
    
    /*string str_2; getline(cin,str_2); cout<<"第二个:"<<str_2<<endl;*/
    
    /*string str_3; getline(cin,str_3,'a'); cout<<"第三个:"<<str_3<<endl;*/
    
    return 0;
}

下面为程序运行结果(三种情况均输入:qweasd zxc)

第一个:qweasd //>>遇到空格结束
第二个:qweasd zxc //getline读取字符,直到遇见文件结束符、分界符、回车符停止
第三个:qwe //getline遇到分界符a 读取结束

3.获取字符串的长度

string 类型对象包括三种求解字符串长度的函数:size() length()maxsize() capacity()

  • size() 和 length():这两个函数会返回 string 类型对象中的字符个数,且它们的执行效果相同。
  • max_size():max_size() 函数返回 string 类型对象最多包含的字符数。一旦程序使用长度超过 max_size() 的 string 操作,编译器会拋出 length_error 异常。
  • capacity():该函数返回在重新分配内存之前,string 类型对象所能包含的最大字符数。跟size()不同,它返回的是分配的容量的大小,并不是string里面字符串的长度。

【例】

#include<iostream>
#include<string>
using namespace std;

int main()
{ 
    string str("abcdef");

    unsigned long size = str.size();
    unsigned long length = str.length();
    unsigned long max = str.max_size();
    unsigned long cap = str.capacity();

    cout<<"size:"<<size<<endl;
    cout<<"length:"<<length<<endl;
    cout<<"max_size:"<<max<<endl;
    cout<<"capacity:"<<cap<<endl;
    return 0;
}

下面为程序输出结果:

size:6
length:6
max_size:9223372036854775807
capacity:15 //至于这里为什么输出15,还不清楚

string 类型对象包括一个 reserve() 函数。调用该函数可以为 string 类型对象重新分配内存(预分配此时不能用下标访问新分配的内存)。重新分配的大小由其参数决定。reserve() 的默认参数为 0。
还包含一个 resize() 函数。其功能与 reserve() 相同,但reserve() 只能将内存扩大,而 resize() 可以任意分配内存(直接分配,如果内存变小,则原字符串被截断,如果内存变大,则用’\0’填充,此时可以用下标访问新分配的内存)。

这两个方法分别对应两个属性:capacity() 和 size()

【例】

#include<iostream>
#include<string>
using namespace std;

int main()
{ 
    string str("abcdef");

    str.reserve(40);
    cout<<"size:"<<str.size()<<endl;
    cout<<"capacity:"<<str.capacity()<<endl;

    str.resize(60);
    //str.shrink_to_fit();
    cout<<str<<endl;
    cout<<"size:"<<str.size()<<endl;
    cout<<"capacity:"<<str.capacity()<<endl;

    str.resize(3);//原字符串被截断
    cout<<str<<endl;

    return 0;
}

下面为程序运行结果:

size:6
capacity:40

abcdef
size:60
capacity:80

abc

上述程序中str.reserve(40);如果将n=40改为0~14,capacity仍输出15,而将n改为15~29时,capacity将输出30。只有改为31及以上,才会输出值n。
此外从运行结果可以看到resize之后,capacity也会发生改变,resize之后(扩大内存)理论上capacity的值与size相同,上述程序由于预先调用了reserve,影响了结果。但是若添加str.shrink_to_fit();,则capacity将会与size相同。

shrink_to_fit()无返回值,功能如下:

请求字符串减小其容量以适合其大小。
该请求是非绑定的,并且容器实现可以自由地进行优化,否则将使字符串的容量大于其大小。
此函数对字符串长度没有影响,并且不能更改其内容。

4.获取字符串元素

字符串中元素的访问是允许的,一般可使用两种方法访问字符串中的单一字符:下标操作符[]成员函数at()。两者均返回指定的下标位置的字符。第 1 个字符索引(下标)为 0,最后的字符索引为 length()-1

需要注意的是,这两种访问方法是有区别的:

  • 下标操作符 [] 在使用时不检查索引的有效性,如果下标超出字符的长度范围,会示导致未定义行为。对于常量字符串,使用下标操作符时,字符串的最后字符(即 ‘\0’)是有效的。对应 string 类型对象(常量型)最后一个字符的下标是有效的,调用返回字符 ‘\0’。
  • 函数 at() 在使用时会检查下标是否有效。如果给定的下标超出字符的长度范围,系统会抛出 out_of_range 异常。
#include<iostream>
#include<string>
using namespace std;

int main()
{ 
    string str("abcdef");

    cout<<str[3]<<endl;
    cout<<str.at(3)<<endl;
    cout<<str[10]<<endl;//越界,返回'\0',但Qt Creator13.01执行时未报错
    cout<<str.at(10)<<endl;//异常

    return 0;
}

运行结果:

d
d

terminate called after throwing an instance of ‘std::out_of_range’
what(): basic_string::at: __n (which is 10) >= this->size() (which is 6)

  • front() 和 back()
    front()back() 分别返回字符串首、尾字符的引用,无参数。
#include<iostream>
#include<string>
using namespace std;

int main()
{ 
    string str("abcdef");

    cout<<str.front()<<endl;
    cout<<str.back()<<endl;

    str.front() = 'c';
    str.back() = 'x';
    cout<<str<<endl;

    return 0;
}

运行结果为:

a
f
cbcdex

另外,为了防止使用下标时,字符串尚未初始化等情况,使用empty() 和 size() 或 length()可以有效防止出错。

empty()无参数,功能如下 :

判断字符串是否为空,是返回真,否则返回假。
  • substr()
    返回子字符串

basic_string substr(size_type pos = 0, size_type n = npos) const;
//返回区间[pos,pos+n-1]的子字符串

    string str("abcdefg");
    cout<<str.substr(2,5)<<endl; //输出cdefg

5.字符串内容的修改

可以通过使用多个函数修改字符串的值。例如 assign()operator=erase()operator+pop_back()swap()insert()等。另外,还可通过 append()push_back()函数添加字符,以及clear()清空字符串。

  • assign()
    使用 assign() 函数可以直接给字符串赋值。该函数既可以将整个字符串赋值给新串,也可以将字符串的子串赋值给新串。其在 basic_string 中的原型为:

basic_string& assign(const char* s); //直接使用C_string字符串赋值

basic_string& assign(const char* s, size_type n);//将C_string字符串s前n个字符赋值给调用串

basic_string& assign (const basic_string& str); //使用string字符串賦值

basic_string& assign(const basic_string& str, size_type pos, size_type n = npos);
//将str的子串赋值给调用串,n表示长度,默认值为-1(直到字符串末尾)

basic_string& assign(size_type n, char c); //使用 n个重复字符賦值

basic_string& assign(InputIterator first, InputIterator last); //使用迭代器赋值

【例】

#include<iostream>
#include<string>
using namespace std;

int main()
{ 
    string str1("123456");
    char s[6] = "abcde";
    string str;

    str.assign(s);//用C_string类型字符串赋值
    cout<<str<<endl;
    str.assign(s,3);//将C_string类型字符串s的前3个字符赋值给str
    cout<<str<<endl;
    str.assign(str1);//用string类型字符串赋值
    cout<<str<<endl;
    str.assign(str1,3);//将str1从第3个字符到最后一个字符赋值给str
    cout<<str<<endl;
    str.assign(str1,2,3);//将str1从第2个字符开始,长度为3的字符串赋值给str
    cout<<str<<endl;
    str.assign(5,'c');//用5个c字符赋值
    cout<<str<<endl;
    str.assign(str1.begin()+2,str1.end()-2);//使用迭代器赋值
    cout<<str<<endl;

    return 0;
}

下面为程序运行结果:

abcde
abc
123456
456
345
ccccc
34

  • operator=
    operator= 的功能就是赋值。

  • operator+
    将两个或多个字符串拼接起来

    string str1("123456");
    string str("789");
    str = str1 + str;
    cout<<str<<endl;//输出123456789
  • push_back()
    在字符串末尾追加一个字符,参数为多个字符时,会被截断

void push_back(char c);

    string str("abc");
    str.push_back('d')
    cout<<str<<endl;//输出abcd
  • swap()
    交换两个字符串的值

void swap (basic_string& str);

    string str1("123456");
    string str("789");
    str.swap(str1);
    cout<<str<<endl; //输出123456
    cout<<str1<<endl;//输出789
  • pop_back()
    删除字符串最后一个字符

void pop_back();

  • erase()
    删除指定子字符串

basic_string& erase(size_type pos = 0, size_type n = npos);
//删除从pos开始,长度为n的子字符串(即区间[pos,pos+n-1]的子字符串)(默认删除全部)

iterator erase(const_iterator position);//使用迭代器,删除指定的一个字符

iterator erase(const_iterator first, const_iterator last);//使用迭代器,删除指定区间的子字符串

#include<iostream>
#include<string>
using namespace std;

int main()
{ 
    string str("123456");
    str.erase(3);//从第3个开始删除后续所有字符
    cout<<str<<endl;

    str = "123456";
    str.erase(3,2);//从第3个开始删除长度为2的子字符串
    cout<<str<<endl;

    str = "123456";
    str.erase(str.begin()+3);//删除第3个字符
    cout<<str<<endl;

    str = "123456";
    str.erase(str.begin()+2,str.begin()+4);//删除区间[2,4)的子字符串
    //str.erase(str.end()-4,str.end()-2); //删除区间{2,4)的子字符串
    cout<<str<<endl;
    return 0;
}

运行结果:

123
1236
12356
1256

  • clear()
    清空字符串,该函数无参数,无返回值。

  • insert()
    向指定位置插入字符串

basic_string& insert(size_type pos, const char* s);//在调用串的第pos个元素前面插入C_string类型字符串

basic_string& insert(size_type pos, size_type n, char c);//在调用串的第pos个元素前面插入n个字符c

iterator insert(const_iterator p, char c);//使用迭代器,在正向迭代器指向的位置p前面插入单个字符c

iterator insert(const_iterator p, size_type n, char c);//在正向迭代器指向的位置p前面插入n个字符c

basic_string& insert(size_type pos, const char* s, size_type n);
//在调用串的第pos个元素前面插入C_string类型字符串s的前n个字符

basic_string& insert(size_type pos1, const basic_string& str, size_type pos2, size_type n = npos);
//在调用串的第pos1个元素前插入字符串str位于区间[pos2,pos2+n -1]的子字符串(n默认直到末尾)

basic_string& insert(size_type pos1, const basic_string& str);//在调用串的第pos1个元素前插入字符串str

iterator insert(const_iterator p, InputIterator beg, InputIterator end);

【例】

#include<iostream>
#include<string>
using namespace std;

int main()
{ 
    string str("123456");
    string ss("vwxyz");
    char s[6] = "abcde";

    str.insert(2,s);//在str第2个元素前面插入C_string类型字符串s
    cout<<str<<endl;

    str = "123456";
    str.insert(2,3,'a');//在str第2个元素前面插入3个字符a
    cout<<str<<endl;

    str = "123456";
    str.insert(str.begin()+1,'b');//在str第1个元素前面插入字符b
    cout<<str<<endl;

    str = "123456";
    str.insert(str.begin(),3,'c');//在str第0个元素前面插入3个字符c
    cout<<str<<endl;

    str = "123456";
    str.insert(3,s,2);//在str第3个元素前面插入c_string类型字符串s的前2位
    cout<<str<<endl;

    str = "123456";
    str.insert(2,ss,2,2);//在str第2个元素前面插入字符串ss从第2个元素开始长度为2的子字符串
    cout<<str<<endl;

    str = "123456";
    str.insert(2,ss);//在str第2个元素前面插入字符串ss
    cout<<str<<endl;

    str = "123456";
    str.insert(str.begin()+1,ss.begin()+3,ss.end());//在str第1个元素前面插入字符串ss从第3个元素到最后一个元素所构成的子字符串
    cout<<str<<endl;

    return 0;
}

程序运行结果为:

12abcde3456
12aaa3456
1b23456
ccc123456
123ab456
12xy3456
12vwxyz3456
1yz23456

  • append()
    追加字符串

basic_string& append(const basic_string& str);//在调用串末尾添加字符串str

basic_string& append(const basic_string& str, size_type pos, size_type n = npos) ;//在调用串末尾添加字符串从第pos个元素开始长度为n的子字符串(即区间[pos,pos+n-1]的子字符串)(n默认直到末尾)

basic_string& append(const char* s, size_type n);//在调用串末尾添加c_string类型字符串s的前n个元素

basic_string& append(const char* s);//在调用串末尾添加c_string类型字符串s

basic_string& append(size_type n, char c);//在调用串末尾添加n个字符c

basic_string& append(InputIterator first, InputIterator last);

【例】

#include<iostream>
#include<string>
using namespace std;

int main()
{ 
    string str("123456");
    string ss("vwxyz");
    char s[6] = "abcde";

    str.append(ss);//在str末尾添加字符串ss
    cout<<str<<endl;

    str = "123456";
    str.append(ss,2,2);//在str末尾添加字符串ss从第2个元素开始长度为2的子字符串
    cout<<str<<endl;

    str = "123456";
    str.append(s,3);//在str末尾添加c_string类型字符串s的前3个字符
    cout<<str<<endl;

    str = "123456";
    str.append(s);//在str末尾添加c_string类型字符串s
    cout<<str<<endl;

    str = "123456";
    str.append(3,'a');//在str末尾添加3个字符a
    cout<<str<<endl;

    str = "123456";
    str.append(ss.begin()+1,ss.end());//在str末尾添加字符串ss在区间[1,4]上的子字符串
    cout<<str<<endl;
    return 0;
}

程序运行结果为:

123456vwxyz
123456xy
123456abc
123456abcde
123456aaa
123456wxyz

6.字符串内容的替换

如果在一个字符串中标识出具体位置,便可以通过下标操作修改指定位置字符的值,或者替换某个子串。完成此项操作需要使用 string 类的成员函数 replace()

replace() 函数的原型如下:

basic_string& replace(size_type pos, size_type n, const basic_string& str);
//将调用串从第pos个元素开始长度为n的子字符串(即区间[pos,pos+n-1]的子字符串)替换为字符串str

basic_string& replace(size_type pos1, size_type n1, const basic_string& str,size_type pos2, size_type n2 = npos);//将调用串从第pos1个元素开始长度为n1的子字符串(即区间[pos1,pos1 + n1 -1]的子字符串)替换为字符串str从第pos2个元素开始长度为n2的子字符串(即区间[pos2,pos2 + n2 -1]的子字符串)(n2默认值指向末尾)

basic_string& replace(size_type pos, size_type n1, const char* s,size_type n2);
//将调用串位于区间[pos,pos+n1 – 1]的子字符串替换为c_string类型字符串s的前n2个字符

basic_string& replace(size_type pos, size_type n1, const char* s);
//将调用串位于区间[pos,pos + n1 -1]的子字符串替换为c_string类型字符串s

basic_string& replace(size_type pos, size_type n1, size_type n2, char c);
//将调用串位于区间[pos,pos + n1 -1]的子字符串替换为n2个字符c

basic_string& replace(const_iterator i1, const_iterator i2, const basic_string& str);
//将迭代器i1,i2指向的元素之间的字符串(包括i1)替换为字符串str

basic_string& replace(const_iterator i1, const_iterator i2,const char* s, size_type n);
//将迭代器i1,i2指向的元素之间的字符串(包括i1)替换为c_string类型字符串s的前n个字符

basic_string& replace(const_iterator i1, const_iterator i2, const char* s);
//将迭代器i1,i2指向的元素之间的字符串(包括i1)替换为c_string类型的字符串s

basic_string& replace(const_iterator i1, const_iterator i2, size_type n, char c);
//将迭代器i1,i2指向的元素之间的字符串(包括i1)替换为n个字符c

basic_string& replace(const_iterator i1, const_iterator i2,InputIterator k1, InputIterator k2);
//将迭代器i1,i2指向的元素之间的字符串(包括i1)替换为迭代器k1,k2指向的元素之间的字符串(包括k1)

basic_string& replace(const_iterator i1, const_iterator i2 , char* k1, char* k2);
//在测试的时候直接输入k2没有作用,要输入k2+(一个常数)表示k2的前几位,在下面的例子会有注释介绍

basic_string& replace(const_iterator i1, const_iterator i2, iterator k1, iterator k2);//使用迭代器替换

【例】

#include<iostream>
#include<string>
using namespace std;

int main()
{ 
    string str("123456");
    string ss("vwxyz");
    char s1[6] = "abcde";
    char s2[6] = "qwert";

    str.replace(2,3,ss);//将str[2,4]的字符串替换为字符串ss
    cout<<str<<endl;

    str = "123456";
    str.replace(2,3,ss,1,3);//将str[2,4]的字符串替换为字符串ss[1,3]
    cout<<str<<endl;

    str = "123456";
    str.replace(1,2,s1,3);//将str[1,2]的字符串替换为c_string类型字符串s1的前3个字符
    cout<<str<<endl;

    str = "123456";
    str.replace(1,2,s1);//将str[1,2]的字符串替换为c_string类型字符串s1
    cout<<str<<endl;

    str = "123456";
    str.replace(3,2,6,'a');//将str[3,4]的字符串替换为6个'a',即aaaaaa
    cout<<str<<endl;

    str = "123456";
    str.replace(str.begin()+1,str.begin()+4,ss);//将str[1,4)的字符串替换为字符串ss
    cout<<str<<endl;

    str = "123456";
    str.replace(str.begin()+1,str.begin()+4,s1,3);//将str[1,4)的字符串替换为c_string类型字符串的前3个字符
    cout<<str<<endl;

    str = "123456";
    str.replace(str.begin()+1,str.begin()+4,s1);//将str[1,4)的字符串替换为c_string类型字符串s1
    cout<<str<<endl;

    str = "123456";
    str.replace(str.begin(),str.begin()+5,6,'c');//将str[0,5)的字符串替换为6个字符c
    cout<<str<<endl;

    str = "123456";
    str.replace(str.begin()+1,str.begin()+3,s1,s2+3);//将str[1,3)的字符串替换为c_string类型字符串s1+s2的前3个字符
    //值的注意的是,s2+n保留s2的前n个字符。而s1+n,则保留s1从第n个字符开始直到末尾的字符串
    //即str.replace(str.begin()+1,str.begin()+3,s1+2,s2+3);//则输出1cdeqwe456
    cout<<str<<endl;

    str = "123456";
    str.replace(str.begin(),str.end(),ss.begin(),ss.end());//将str替换为ss
    cout<<str<<endl;
    return 0;
}

以下为程序运行结果:

12vwxyz6
12wxy6
1abc456
1abcde456
123aaaaaa6
1vwxyz56
1abc56
1abcde56
cccccc6
1abcdeqwe456
vwxyz

7.字符串的比较

字符串可以和类型相同的字符串相比较,也可以和具有同样字符类型的数组比较。

basic_string 类模板既提供了 >、<、==、>=、<=、!= 等比较运算符,还提供了 compare() 函数,其中 compare() 函数支持多参数处理,支持用索引值和长度定位子串进行比较。该函数返回一个整数来表示比较结果。如果相比较的两个子串相同,compare() 函数返回 0,大于返回正值,小于返回负值。

  • compare()
    比较两字符串大小

类 basic_string 的成员函数 compare() 的原型如下:

int compare(const basic_string& str) const;//直接与str比较

int compare(size_type pos, size_type n, const basic_string& str) const;
//调用串在区间[pos,pos+n-1]上的子字符串与字符串str比较

int compare(size_type pos1, size_type n1, const basic_string& str,size_type pos2, size_type n2 = npos) const;//调用串在区间[pos1 , pos1 + n1 -1]上的子字符串与字符串str在区间[pos2,pos2+n2 – 1]上的子字符串比较(n2默认指向末尾)

int compare(const char* s) const; //直接与c_string类型的字符串s比较

int compare(size_type pos, size_type n1, const char* s) const;
//调用串在区间[pos,pos+n1 – 1]上的子字符串与c_string类型字符串s比较

int compare(size_type pos, size_type n1, const char* s,size_type n2) const;
//调用串在区间[pos,pos+n1 – 1]上的子字符串与c_string类型字符串s的前n2个字符比较

【例】

#include<iostream>
#include<string>
using namespace std;

string comp(int result)
{ 
    if(result==0)
        return "=";
    else if (result>0)
        return ">";
    else
        return "<";
}

int main()
{ 
    string str("123456");
    string ss("1234");
    char s[6] = "123ab";
    int result;

    result = str.compare(ss);//123456与1234比较
    cout<<comp(result)<<endl;

    result = str.compare(0,5,ss);//12345与1234比较
    cout<<comp(result)<<endl;

    result = str.compare(0,2,ss,2,2);//12与34比较
    cout<<comp(result)<<endl;

    result = str.compare(s);//123456与123ab比较
    cout<<comp(result)<<endl;

    result = str.compare(0,3,s);//123与123ab比较
    cout<<comp(result)<<endl;

    result = str.compare(0,3,s,3);//123与123比较
    cout<<comp(result)<<endl;
    return 0;
}

下面为程序运行结果:

>
>
<
<
<
=

  • 重载操作符<,>,==,<=,>=,!=
    与数字的比较相同,不再赘述

值得一提的是字符串比较规则:

  1. 字符串比较大小并不是比较二者的长度。
  2. 字符串比较大小,从左数第一个字符开始进行比较
  3. 进行比较的是两字符的ASCII码的大小
  4. 逐一进行比较,如果出现差异直接结束比较,否则继续比较下一个字符,直到某一个字符串结束

8.字符串的查找

在 C 语言和 C++ 语言中,可用于实现字符串查找功能的函数非常多。在 STL 中,字符串的查找功能可以实现多种功能,比如说:

  • 搜索单个字符、搜索子串;
  • 实现前向搜索、后向搜索;
  • 分别实现搜索第一个和最后一个满足条件的字符(或子串);

若查找 find() 函数和其他函数没有搜索到期望的字符(或子串),则返回 npos;若搜索成功,则返回搜索到的第 1 个字符或子串的位置。其中,npos 是一个无符号整数值,初始值为 -1。当搜索失败时, npos 表示“没有找到(not found)”或“所有剩佘字符”。

值得注意的是,所有查找 find() 函数的返回值均是 size_type 类型,即无符号整数类型。该返回值用于表明字符串中元素的个数或者字符在字符串中的位置。

下面分别介绍和字符查找相关的函数。

  • find()和rfind()

find() 函数的原型有以下 4 种:

size_type find(const char* s, size_type pos, size_type n) const;
//第1个参数是被搜索的字符串,第2个参数是源串中开始搜索的下标,第3个参数是关于第1个参数的字符个数,可能是 s 的所有字符数,也可能是 s 的子串宇符个数

size_type find(const basic_string& str, size_type pos = 0) const;
//find()函数的第1个参数是被搜索的字符串,第2个参数是在源串中开始搜索的下标位置,默认从头开始搜索

size_type find(const char* s, size_type pos = 0) const;
//同上,搜索c_string类型字符串

size_type find(char c, size_type pos = 0) const;
//第1个参数是被搜索的单个字符,第2参数是在源串中开始搜索的下标位置,默认从头开始搜索

rfind() 函数的原型和find()函数的原型类似,参数情况也类似。只不过 rfind() 函数适用于实现逆向查找。

【例】

#include<iostream>
#include<string>
using namespace std;

int main()
{ 
    string str("Try not to become a man of success "
               "but rather try to become a man of value");

    string search("but");

    string::size_type position1 = str.find("best");
    string::size_type position2 = str.find('o');
    string::size_type position3 = str.find("todoit",0,2);
    cout<<static_cast<int>(position1)<<endl;
    cout<<static_cast<int>(position2)<<endl;
    cout<<static_cast<int>(position3)<<endl;

    string::size_type position4 = str.rfind(search);
    string::size_type position5 = str.rfind('o');
    string::size_type position6 = str.rfind("todoit",string::npos,2);
    cout<<static_cast<int>(position4)<<endl;
    cout<<static_cast<int>(position5)<<endl;
    cout<<static_cast<int>(position6)<<endl;
    return 0;
}
  • find_first_of()和 find_last_of()

find_first_of() 函数可实现在源串中搜索某字符串的功能,该函数的返回值是被搜索字符串的某 1 个字符第 1 次出现的下标(位置)。若查找失败,则返回 npos。

size_type find_first_of(const basic_string& str, size_type pos = 0) const;
//搜索str字符串中的字符第一次在调用串中出现的位置,pos为搜索起点,默认从头开始

size_type find_first_of(const char* s, size_type pos, size_type n) const;
//搜索c_string类型字符串s的前n个字符第一次在调用串中出现的位置,pos为搜索起点

size_type find_first_of(const char* s, size_type pos = 0) const;
//搜索c_string类型字符串s中的字符第一次在调用串中出现的位置,pos为搜索起点,默认从头开始

size_type find_first_of(char c, size_type pos = 0) const;
//搜索字符c第一次在调用串中出现的位置,pos为搜索起点,默认从头开始

find_last_of() 函数同样可实现在源串中搜索某字符串的功能。函数的原型和find_first_of()函数的原型类似,参数情况也类似。与 find_first_of() 函数所不同的是,该函数的返回值是被搜索字符串的最后 1 个字符的下标(位置)。若查找失败,则返回 npos。

  • find_first_not_of()和 find_last_not_of()

find_first_not_of() 函数可实现在源字符串中搜索与指定字符(串)不相等的第 1 个字符;
find_last_not_of() 函数可实现在源字符串中搜索与指定字符(串)不相等的最后 1 个字符。
这两个函数的参数及意义与find_first_of() 和 find_last_of()相同,不再赘述。

【例】

#include<iostream>
#include<string>
using namespace std;

int main()
{ 
    string str("Try not to become a man of success "
               "but rather try to become a man of value");
    string search("but");
    char sh[5] = "some";
    string::size_type position1 = str.find_first_of("best");
    string::size_type position2 = str.find_first_of(sh,34,1);//从str[34]开始搜索第一个为s的字符
    string::size_type position3 = str.find_first_of(sh,0);
    string::size_type position4 = str.find_first_of('v');
    cout<<static_cast<int>(position1)<<endl;
    cout<<static_cast<int>(position2)<<endl;
    cout<<static_cast<int>(position3)<<endl;
    cout<<static_cast<int>(position4)<<endl;

    string::size_type position5 = str.find_first_not_of(" abcTrynot");
    string::size_type position6 = str.find_first_not_of(sh,0,2);//搜索第一个不是s,o,m的字符
    string::size_type position7 = str.find_first_not_of(sh,0);//从str的头开始搜索第一个不是s,o,m,e的字符
    string::size_type position8 = str.find_first_not_of('e');//搜索第一个不是e的字符
    cout<<static_cast<int>(position5)<<endl;
    cout<<static_cast<int>(position6)<<endl;
    cout<<static_cast<int>(position7)<<endl;
    cout<<static_cast<int>(position8)<<endl;

    string::size_type position9 = str.find_last_of(" abcTrynot");
    string::size_type position10 = str.find_last_of(sh,string::npos,2);
    string::size_type position11 = str.find_last_of(sh,string::npos);
    string::size_type position12 = str.find_last_of('e');
    cout<<static_cast<int>(position9)<<endl;
    cout<<static_cast<int>(position10)<<endl;
    cout<<static_cast<int>(position11)<<endl;
    cout<<static_cast<int>(position12)<<endl;

    string::size_type position13 = str.find_last_not_of(" abcTrynot");
    string::size_type position14 = str.find_last_not_of(sh,string::npos,3);
    string::size_type position15 = str.find_last_not_of(sh,string::npos);
    string::size_type position16 = str.find_last_not_of('e');
    cout<<static_cast<int>(position13)<<endl;
    cout<<static_cast<int>(position14)<<endl;
    cout<<static_cast<int>(position15)<<endl;
    cout<<static_cast<int>(position16)<<endl;
    return 0;
}

程序运行结果为:

6
-1
5
69
12
0
0
0
70
66
73
73
73
73
72
72

9.string支持迭代器

迭代器(iterator)是一种对象,它能够用来遍历标准模板库容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址。迭代器修改了常规指针的接口,所谓迭代器是一种概念上的抽象:那些行为上像迭代器的东西都可以叫做迭代器。然而迭代器有很多不同的能力,它可以把抽象容器和通用算法有机的统一起来。

迭代器提供一些基本操作符:*、++、==、!=、=。这些操作和C/C++“操作array元素”时的指针接口一致。不同之处在于,迭代器是个所谓的复杂的指针,具有遍历复杂数据结构的能力。其下层运行机制取决于其所遍历的数据结构。因此,每一种容器型都必须提供自己的迭代器。事实上每一种容器都将其迭代器以嵌套的方式定义于内部。因此各种迭代器的接口相同,型号却不同。这直接导出了泛型程序设计的概念:所有操作行为都使用相同接口,虽然它们的型别不同。

STL 定义了 5 种迭代器,根据所需的迭代器类型对算法进行描述。这 5 种迭代器分别是:输入迭代器 输出迭代器 正向迭代器 双向迭代器 随机访问迭代器。对于这 5 种迭代器不仅可以执行解除引用操作(* 操作符),还可进行比较。这里主要讲述 basic_string(或 string 类)中迭代器的使用。

basic_string 和 string 类均提供了常规的迭代器和反向迭代器。string 是字符的有序群集。

C++ 标准库为 string 提供了相应接口,便于将字符串作为 STL 容器使用。可以使用迭代器遍历 string 内的所有字符;也可以使用其他算法遍历 string 内的所有字符。而且能够访问字符串中的每个字符,并对这些字符进行排序、逆向重排、找出最大值等操作。

string 类的迭代器是随机存取迭代器,即支持随机存取。任何一个 STL 算法都可与其搭配使用。通常 string 的“迭代器型别”由 string 类本身定义,通常可以被简单地定义为一般指针。对迭代器而言,如果发生重新分配,或其所指的值发生某些变化时,迭代器会失效。

string 类中和使用迭代器相关的成员函数是很多的,主要包括 begin()、end()、rbegin ()、rend()、append()、assign()、insert()、erase()、replace() 等。

名称功能
begin( )返回指向字符串第一个字符的迭代器。
end()返回指向字符串最后一个字符(’\0’)的迭代器。
cbegin()返回指向字符串第一个字符的const类型迭代器。
cend()返回指向字符串最后一个字符(’\0’)的const类型迭代器。
rbegin()返回一个反向迭代器,该迭代器指向字符串的最后一个字符(即它的反向开始)。
rend()返回一个反向迭代器,该迭代器指向字符串第一个字符之前的理论元素(该字符被视为反向元素)。
crbegin()返回一个const类型反向迭代器,该迭代器指向字符串的最后一个字符(即它的反向开始)。
crend()返回一个const类型反向迭代器,该迭代器指向字符串第一个字符之前的理论元素(该字符被视为反向元素)。

begin()与cbegin()的区别是 begin()指向非const的字符串时,可以对其进行修改,而cbegin()只能指向const类型字符串(即开头的c表示const,r表示reverse)。其余同上。

#include<iostream>
#include<string>
#include<algorithm>
#include<iterator>
using namespace std;

int main()
{ 
    string str("Standing up to your own."
               "That would take a real hero.");
    cout<<str<<endl;

    string::iterator it;//使用正向迭代器遍历字符串
    for(it = str.begin();it!=str.end();it++)
        cout<<*it;
        //function();//可以进行其他操作
    cout<<endl;

    string::reverse_iterator rev_it;//使用反向迭代器倒序输出字符串
    for(rev_it = str.rbegin();rev_it!=str.rend();rev_it++)
        cout<<*rev_it;
        //function();//可以进行其他操作
    cout<<endl;

    std::ostreambuf_iterator<char> out_it(std::cout);//使用输出流迭代器正序输出字符串
    std::copy(str.begin(),str.end(),out_it);
    cout<<endl;

    std::ostreambuf_iterator<char> rev_out_it(std::cout);//使用输出流迭代器倒序输出字符串
    std::copy(str.rbegin(),str.rend(),rev_out_it);
    cout<<endl;

    //还有各种函数中使用迭代器,在上文已经涉及

    return 0;
}

程序运行结果为:

Standing up to your own.That would take a real hero.
Standing up to your own.That would take a real hero.
.oreh laer a ekat dluow tahT.nwo ruoy ot pu gnidnatS
Standing up to your own.That would take a real hero.
.oreh laer a ekat dluow tahT.nwo ruoy ot pu gnidnatS

资料来源

  1. The C++ Resources Network(http://www.cplusplus.com
  2. C语言中文网(http://m.biancheng.net
  3. 百度百科 (https://baike.baidu.com/item/capacity/6299959
  4. 百度百科 (https://baike.baidu.com/item/%E8%BF%AD%E4%BB%A3%E5%99%A8
    原文作者:Eloik
    原文地址: https://blog.csdn.net/weixin_45826022/article/details/102865814
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞