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字符遍历的方法,并总结了一些使用小技巧。