IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

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

    轻口味发表于 2024-06-25 10:32:46
    love 0

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



沪ICP备19023445号-2号
友情链接