2

1. 背景介绍

在Java中操作字符串比较简单,这里简单介绍下Java字符串操作相关接口。

字符串拼接直接用+号既可,字符串比较实用equel方法,同时还提供了StringBuilder和StringBuffer可变的字符串。它们继承了同一个抽象的字符串父类:AbstractStringBuilder

StringBuffer是线程安全,StringBuilder线程不安全。因为 StringBuffer 的所有公开方法都是 synchronized 修饰的,而 StringBuilder 并没有 synchronized修饰;StringBuffer 每次 toString 都会直接使用缓存区的 toStringCache 值来构造一个字符串,而 StringBuilder 则每次都需要复制一次字符数组,再构造一个字符串。所以,缓存冲这也是对 StringBuffer 的一个优化吧,不过 StringBuffer 的这个toString 方法仍然是同步的。

在C语言中我们操作String要相对麻烦些,每次字符串拼接都要重新开辟空间,再把数据拷贝进去,使用上没有那么便捷。

C++标准库中为我们实现了std::string字符串类,本文我们系统的介绍std::string类。

2. 初始化std::string

string也是C++的一个类,跟其他普通类类似,string也提供了以下几种初始化方法:

#include <string>
using std::string;
//默认初始化成空字符串
string s1;
//拷贝初始化,等价于string s2(s1);
string s2=s1;
//拷贝初始化,是字符串字面值的副本,等价于string s3("hello");
string s3 = "hello";
//初始化为由连续n个字符c组成的串
string s4(3,'a');

3. string常用操作

C++中定义在类上的操作除了方法还有操作符,这里我们介绍C++常用操作。

3.1 读写string

读写string主要用到string类上定义的操作符:<<>>:

string s;
//将标准输入内容写入到自字符串s
cin >> s;
//将字符串输出给标准输出
count << s << end;

string对象的<<>>操作返回运算符左侧的运算对象作为结果:

string s1,s2;
//第一个输入写到s1,第二个输入写到s2
cin >> s1 >> s2;
cout << s1 << s2 <<endl;

与标准输入输出相关的还有读取一行,使用getline方法:

string str;
getline(cin, line);

3.2 获取字符串长度

通过成员变量size获取字符串长度;

还可以通过empty函数判断string对象字符数是否为零。

size函数返回的不是int或者unsinged int,二是返回的是string::size_type类型。

为什么要有这么一个类型呢?因为这样定义提箱了标准库类型与机器无关的特性。

注意:其实size函数返回的还是一个无符号整形,只是做了一层封装,因此我们在表达式计算中要避免既有size返回类型的同时又有int型。因为例如,假设x是一个具有负值的int,则表达式s.size()< x的判断结果肯定是true,因为负值x会自动地转换成一个比较大的无符号值。

3.3 string字符串的比较

java中我们不能用==来比较两个字符串,它比较的是地址,要用equal。在C++中用相等性运算符(==和!=)来检验两个string对象是否相等。相等意味着它们的长度相同并且所包含的字符也全相同。

C++中还可以用关系运算符<、<=、>、>=来检验一个string对象是否小于、小于等于、大于、大于等于另外一个string对象。

3.4 字符串相加

两个string对象相加得到一个新的string对象,其内容是把左侧的运算对象与右侧的运算对象串接而成。这个和Java中字符串相加很类似。

C++标准库允许把字符字面值和字符串字面值转换成string对象,所以在需要string对象的地方可以使用这两种字面值来替代。比如:

string s1 = "hello";
string s2 = "world";
string s3 = s1 + "," + s2 + "\n";

注意:当把string对象、字符字面值、字符串字面值在一条语句中相加时,必须确保每个加法运算符(+)的两侧的运算对象至少有一个是string。比如:

string s = "hello" + "world";//错误
string s1 = "world";
string s2 = "hello" + "," + s1;//错误

虽然我们不会去这样搞,但是也要知道这种是有语法错误的。

有这个问题的原因是C++为了与C兼容,C++语言的字符串字面值并不是标准库类型string的对象。字符串字面值与string不是同样的类型。

4. string的字符遍历

string其实可以理解成一个字符的集合,既然是集合就要涉及遍历。比如将string中所有字符变为小写,查看特定字符是否存在等。

在cctype头文件中定义了一组标准库函数做字符处理相关工作:

  • isalnum:是否为字母或数字
  • isalpha:是否为字母;
  • iscntrl:是否为控制字符
  • isdigit:是否为数字
  • isgraph:不是空格但可打印
  • islower:是否是小写字母
  • isprint:是可打印字符
  • ispunct:是否是标点符号
  • isspace:是否为空白(空格、制表符、回车、换行、进纸)
  • isupper:是否为大写
  • isxdigit:是否是十六进制数字
  • tolower:如果是大写字母,返回对应小写字母
  • toupper:如果是小写字母,返回对应大写字母

最佳实践: C++标准库中除了定义C++语言特有的功能外,也兼容了C语言的标准库。比如C语言的头文件为name.h,C++则命名为cname。建议使用C++版本的C标准库头文件。

遍历字符串,可以使用for语句:

for(declaration: expression)
    statement

示例:

string str("1234566");
for(auto c : str){
    cout << c <<endl;
}

但是如果我们想要改变string对象中的字符的值,必须把循环变量定义成引用类型:

string s("ABCDEFG");
//转换成小写
for(auto &c : s){
    c = tolower(c);
}
cout << s << endl;

除了使用for循环,还可以使用下标运算符[]访问字符串中特定位置的字符,返回值是该位置上字符的引用(因为是引用所以我们可以直接改变这个值):

cout << s[0] << endl;

不像Java如果下标越界直接崩溃,C++中如果下标越界将引发不可预知的结果,所以我们在使用下标运算符时一定要对下标范围做判断。

最佳实践:任何表达式只要它的值是一个整形就能作为索引。如果某个索引是带符号类型的值将自动转换成由string::size_type表达的无符号类型。有一个简单的技巧,我们总是设下标类型为string:size_type,因为它是无符号数,可以确保下标不会小于0,只要保证下标小于size()的值即可。

5.总结

本文介绍了C++标准库std::string的基本操作以及常用的函数,介绍了string字符遍历的方法,并总结了一些使用小技巧。


轻口味
16.9k 声望3.9k 粉丝

移动端十年老人,主要做IM、音视频、AI方向,目前在做鸿蒙化适配,欢迎这些方向的同学交流:wodekouwei