引用

  • std:string

前言

回忆过C语言版的字符串

1
2
char ch[] = "abafjiafajif";
char ch[10] = "aaaaaaaa";

大致上一个意思,限定长度和不限定长度,不限定长度会自动根据初始化的值长度而定义。

其次就是拼接两个字符串

1
2
3
4
5
6
char ch[10] = "1234";
char ch1[10] = "5678";
char ch2[20];

memcpy(ch2, ch, strlen(ch)); //先将ch从头拷贝进来
memcpy(ch2 + strlen(ch), ch1, strlen(ch1) + 1); //在由从ch拷贝到ch2里

这样拼接起来还是挺麻烦的,如果能直接相加赋给字符串就会相对方便了。


正文

1
2
3
4
5
6
7
8
#include<iostream>
#include<string>
using std::string;

int main(){

return 0;
}

使用string关键字前需包含头文件string,此外如果不想老是写std::string,就在下面加一句using std::string;.

1
2
string str = "hello world";
std::cout << str << std::endl;

定义起来格式就跟正常变量一样。输入输出相较于C语言类型的字符串的好处就是,不用提前声明大小,不用担心随便溢出。

此外string还可以指定只接受字符串的一部分

1
2
string str{ "hello world" , 5};
std::cout << str << std::endl;

除了从0开始,还能自定义:

1
2
string str = { "hello world" , 1,3};
std::cout << str << std::endl;

能从指定的字符串获取,也就能从变量获取

1
2
3
4
string str;
std::cin >> str;
string str1 = { str,2,5 };
std::cout << str1 << std::endl;

像比较之下方便了许多,但是这其实也就是官方封装好的,自己也能实现类似的效果

ps:对中文支持一般,因为字符集的不确定性,不能保证不同占用下带来的问题

还有一种比较无聊的写法:

1
string str(6,'a');

就是赋值了6个’a’组成的字符串。

然后回到拼接字符串,string可以直接通过相加实现

1
2
3
string str = "1234";
string str1;
str1 = str + "5678";

效果也是ok的。

当然要求+的时候都是字符串,不能是字符串以外的东西

如果想加一串数字,那也只能先将其转换成字符串。

1
string str = to_string(123);

这样得到的str就是“123”,一个字符串类型的变量。

当然数字不单只是整型的,小数也可以。


加强

字符串拼接存在一个问题,那就是参数不能都是常量

1
2
string str;
str = "123" + "456";

这种情况下就会报错,原因是这两个常量“123”和“456”在计算机里还是char类型的
解决办法可以创建临时变量或者强转

1
2
3
string str;
str = (string)"123" + "456"; //强制转换
str = string{"123"} + "456"; //创建临时string的变量

如果使用+=操作符,那么也要注意类型转换,因为+的优先级高于+=

1
2
3
string str;
str = string{ "123" } + "456" + "789";
str += (string)"hhh" + "aaa"; //保持强制转换或者创建临时变量

append

之前的拼接都是使用+号,还得额外创建一个变量,string本身提供了一种方法就是append

1
2
3
4
string str = "123";
str.append("456");

std::cout << str << std::endl;

同时append可以套娃str.append("123").append("456").append("789").....
也可以截取str.append("123456",3)或者str.append("123456",2,5)
也可以使用定义时的办法str.append(6,'a')

抛开使用中的一种,也就意味着append有七种参数方法。


substr

字符串的截取方法

1
2
.substr(index,end); //输入截取的起点和终点
.substr(index); //只输入一个数则表示截取起点,默认截取到最后

substr会有一个返回值,返回的值就是截取后的字符串,可以用于赋值给其他字符串或者直接打印

1
2
3
4
string str = "0123456789";
string str1 = str.substr(1,5);
std::cout << str.substr(1,5) << std::endl;
std::cout << str1 << std::endl;

效果就是:


length

C语言我们计算字符串长度使用strlen,cpp的string则也有计算长度的方法length

1
2
string str = "0123456789";
std::cout << str.length() << std::endl;

效果就是:
当然length的返回值也可以赋值给一个int类型的变量,以作重复使用。

然后同样的问题,对中文的支持都是很玄学,毕竟各字符集对中文占用大小并不统一


[]

string也可以通过[]去访问字符串成员,下标依然0起,底层实现也是类似的,使用的内存空间也是连续的。
就没什么必要演示了


判断

1
2
3
4
char *ch = (char*)"123456";
char *ch1 = (char*)"123456";
if(ch == ch1)
std::cout << "=" << std::endl;

在C语言里,字符串其实没有一个很准确的比较功能,像上述的代码中,能够判断也是因为二者的初始化时相当于使用了常量,而编译器恰好优化了常量,使常量的地址一致,所以才会判断相等
结果就是:

反汇编看两个初始值的情况

可以看到”123456“的十六进制值是相同的,所以比较的时候才相等。
但是这种比较方法很显然不靠谱。防止编译器优化的话,就需要其中一个字符串通过手动输入,这样就不能一下子确认为是常量。

但其实也有一个方法strcmp,不过就得借用string.h头文件了,也就是变相借助了工具,所以说原生下没有这种功能。
int strcmp(const char* str1,const char* str2);
返回值:

  • 如果返回值 < 0,则表示 str1 小于 str2。
  • 如果返回值 > 0,则表示 str2 小于 str1。
  • 如果返回值 = 0,则表示 str1 等于 str2。

而string的话,它肯定是内置了不少方法的:== != > < >= <=
原则就是根据顺序,依次比较字符大小,在第一个字符就分出大小则就无视后面的字符,如果第一个字符相等就往后比较以此类推。


compare

string类型自带的方法,返回值是int类型的值

  • 两个字符串完全相等返回0
  • 相比比较的字符串小返回负数
  • 相比比较的字符串大返回正数

所以if的时候要注意,因为使用compare如果相等返回的是0,0在C语言cpp里面是表示假的。

.compare(index, end, str)这是一个拓展的参数,可以指定被比较的字符串从哪里开始到哪里结束。


find

.find(str),find的返回值是一个整型,它可以找到str第一次出现的下标。

使用场景的话,最常用的就是substr的时候,找到原字符串内的某一块内容,用find当起始值。
.find(str,index) 从要比较的字符串的index处包括index开始查找,返回值是std::string::npos 可能是-1或者4294967295
.find(str,index,end) 从要被比较的字符串index处开始查找,范围是{str[0],str[end]}


rfind

这玩意。。就是倒着搜的find。
所以指定index的时候要从最后面开始,从0开始没遇到直接就罢工了。。
这玩意用的真的挺少的感觉。


insert

string的插入方法,参数小多
.insert(要插入的位置,要插入的字符串,要插入的字符串起始位置,要插入的大小);
.insert(要插入的位置,要插入的字符串,要插入的大小);

1
2
string str = "abc,";
str.insert(3,"123",3);

replace

string的内置方法,可以指定替换string中的内容
.replace(index, length, "str")
.replace(index, length, "char length", char)
.replace(起始位置,要替换长度,替换内容,替换后容节选长度)
.replace(起始位置,要替换长度,替换内容,替换后内容的起始位置,替换后容节选长度)

例一:

1
2
string str = "id=001;";
str.replace(3, 4, "003");

那么打印str之后的内容就会是id=003

例二:

1
2
string str = "abcde;";
str.replace(3, 4, 6, '*');

那么打印str之后的内容就会是abc******;

例三:

1
2
string str = "id=001;";
str.replace(3,4,"zhangsan;name=hhh;",8);

str为id=zhangsan;

例四:

1
2
string str = "id=001;";
str.replace(3,4,"zhangsan;name=hhh;",5,8);

str为id=san;

其实后面几个用的也不多


.erase

能替换,也能删除
.erase(删除的起始位置)
.erase(删除起始位置,删除的长度)

1
2
string str = "id=001;"
str.erase(3);

str显示为id=

1
2
string str = "id=001;"
str.erase(3,4);

str显示为id=


clear

顾名思义就是清除,对应的就是清空字符串的内容。
就不演示了,反正使用了之后在打印字符串就是空的


练习

string str = "id=xxx;name=xxx;sex=x;phone=xxxxxxx;";
假设有这么一句字符串,需要你实现输入选项如id,拆解出id=后面的参数,不含;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int main(){
string str = "id=1;name=hhh;sex=1;phone=110154654";
string sIN,sOut;

std::cout << "请输入查找关键字:\n";
std::cin >> sIn;
int flag = str.find("sIn"+"="); //加上等于才是完整的表达式
if(flag == std::string::nopos)
std::cout << "所查找关键字不存在!\n";
else{
int len = str.find(";",flag);
sOut = str.substr(flag + sIn.length()+1, len - flag - sIn.length()-1);
std::cout << sOut << std::endl;
}


return 0;
}

结语

内置的方法还是香的,自己能造出轮子也不失为一种办法。