写点什么

Android C++ 系列:string 最佳实践

作者:轻口味
  • 2022 年 4 月 25 日
  • 本文字数:2420 字

    阅读完需:约 8 分钟

Android C++系列:string最佳实践

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;//将标准输入内容写入到自字符串scin >> s;//将字符串输出给标准输出count << s << end;
复制代码


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


string s1,s2;//第一个输入写到s1,第二个输入写到s2cin >> 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 字符遍历的方法,并总结了一些使用小技巧。

发布于: 2022 年 04 月 25 日阅读数: 16
用户头像

轻口味

关注

🏆2021年InfoQ写作平台-签约作者 🏆 2017.10.17 加入

Android、音视频、AI相关领域从业者。 欢迎加我微信wodekouwei拉您进InfoQ音视频沟通群 邮箱:qingkouwei@gmail.com

评论

发布
暂无评论
Android C++系列:string最佳实践_c++_轻口味_InfoQ写作社区