Abseil系列五:strings(字符串工具库)

简介

因stl中未包含一些字符串分割,合并的算法或者算法不太高效,这些功能在字符串操作中也经常被用到,在absl/strings都有提供。本章概述了strings库的一般用法,以及平时开发常用到的一些很实用的字符串函数。更多信息参见官网介绍源代码(absl/strings目录)

使用

  • absl::string_view

    string_view,顾名思义,提供关联字符串数据的只读视图。通常在您需要访问字符串数据,但不需要拥有它,也不需要修改它是使用。使用时包含absl/strings/string_view.h。

    string_view一般用于常量等,由于生命周期问题,string_view通常是返回值的糟糕选择,对于数据成员也是如此。 如果您确实以这种方式使用一个,那么您有责任确保string_view不会比它所指向的对象活得更久。

    string_view对象是非常轻量级的,所以你应该总是在你的方法和函数中按值传递它们; 不要传递const absl::string_view &。 (传递absl::string_view而不是const absl::string_view &具有相同的算法复杂性,但由于寄存器分配和参数传递规则,在这种情况下通常按值传递更快。)

  • 字符串分割:absl::StrSplit()

    absl::StrSplit()函数提供了一种将字符串拆分为子字符串的简单方法。使用时包含absl/strings/str_split.h。函数使用如下:

    // 参数1:要拆分的输入字符串
    // 参数2:分隔符,有4中类型:
    // 		ByString:指定分割的字符串,因字符串会被转换absel::ByString类,所以absl::ByString(",")和直接使用","等同。
    // 		ByChar:指定分割的字符,absl::ByChar(',')和直接使用','等同。
    // 		ByAnyChar:指定风格的字符串,只要要才分的输入字符串中包含分割字符串中的字符,都将被分割。absl::ByAnyChar(",=")
    // 		ByLength:按指定的长度分割。absl::ByLenth(5)将会按5个字符的长度风格
    //		MaxSplits:分割指定次数,比如指定分割为:absl::MaxSplits(',', 1),
    // 参数3:可选默认AllowEmpty。
    //      absl::AllowEmpty返回结果列表包含空字符串, 
    //      absl::SkipEmpty返回结果列表不包含空,
    //      absl::SkipWhitespace():返回结果列表不包含空格的字符串,不包含空字符串;
    // 返回值:所有标准的STL容器,包括std::vector, std::list, std::deque, std::set, std::multiset, std::map, std::multimap,甚至std::pair。容器的数据内容为字符串。
    std::vector<std::string> v = absl::StrSplit(" a , ,,b,", absl::ByChar(','), absl::SkipWhitespace());
    
  • absl::StrCat()

    1. absl::StrCat()将任意数量的字符串或数字合并到一个字符串中。使用时包含absl/strings/str_cat.h。

    2. absl::StrCat()的优点:

      • 高效:C++修改字符串的开销可能很大,因为字符串通常包含大量的数据,而且许多模式涉及到创建临时副本,这可能会带来很大的开销。absl::StrCat()和absl::StrAppend()通常比+=等操作符更高效,因为它们不需要创建临时std::string对象,并且在字符串构造过程中预先分配它们的内存。

      • 支持数据类型格式化

        支持的类型如下:

        • std::string

        • absl::string_view

        • 字符串

        • 数值类型 (floats, ints),浮点类型6位精度,当幅度小于0.001或大于或等于1e+6时使用“e”格式

        • 布尔 (convert to “0” or “1”)

        • 二进制:Hex values through use of the absl::Hex() conversion function

    3. 使用演示:

      std::string s1 = "value1";
      absl::string_view s2 = "value2";
      auto result = absl::StrCat(s1, ",",
                                 s2, ",",
                                 "value3", ",",
                                 4, ",",
                                 5.1f, ",",
                                 true, ",",
                                 absl::Hex(10, absl::kZeroPad2), ",",
                                 absl::Dec(11, absl::kZeroPad10));
      std::cout << result << std::endl;
      
      // 输出结果为:value1,value2,value3,4,5.1,1,0a,0000000011
      
  • 字符串追加:absl::StrAppend()

    将一个字符串或一组字符串追加到现有的字符串中 。使用时包含absl/strings/str_cat.h。其他使用同absl::StrCat()

    std::string s1 = "value1";
    absl::string_view s2 = "value2";
    std::string result = "the result:";
    
    absl::StrAppend(&result, ",",
                    s2, ",",
                    "value3", ",",
                    4, ",",
                    5.1f, ",",
                    true, ",",
                    absl::Hex(10, absl::kZeroPad2), ",",
                    absl::Dec(11, absl::kZeroPad10));
    
    std::cout << result << std::endl;
    
    // 输出结果为:the result:,value2,value3,4,5.1,1,0a,0000000011
    
  • 字符串合并:absl::StrJoin()

    字符串合并。使用时包含absl/strings/str_join.h。

    #include "absl/strings/str_join.h"
    
    #include <iostream>
    #include <map>
    #include <vector>
    
    int main(int argc, char *argv[])
    {
        {
            //Example 1:
            // Joins a collection of strings. This pattern also works with a collection
            // of `absl::string_view` or even `const char*`.
            std::vector<std::string> v = {"foo", "bar", "baz"};
            std::string s = absl::StrJoin(v, "-");
            // 输出:foo-bar-baz
            std::cout << s << std::endl;
        }
    
        {
            //Example 2:
            // Joins the values in the given `std::initializer_list<>` specified using
            // brace initialization. This pattern also works with an initializer_list
            // of ints or `absl::string_view` -- any `AlphaNum`-compatible type.
            std::string s = absl::StrJoin({"foo", "bar", "baz"}, "-");
            // 输出:foo-bar-baz
            std::cout << s << std::endl;
        }
    
        {
            //Example 3:
            // Joins a collection of ints. This pattern also works with floats,
            // doubles, int64s -- any `StrCat()`-compatible type.
            std::vector<int> v = {1, 2, 3, -4};
            std::string s = absl::StrJoin(v, "-");
            // 输出:1-2-3--4
            std::cout << s << std::endl;
        }
    
        {
            //Example 4:
            // Joins a collection of pointer-to-int. By default, pointers are
            // dereferenced and the pointee is formatted using the default format for
            // that type; such dereferencing occurs for all levels of indirection, so
            // this pattern works just as well for `std::vector<int**>` as for
            // `std::vector<int*>`.
            int x = 1, y = 2, z = 3;
            std::vector<int*> v = {&x, &y, &z};
            std::string s = absl::StrJoin(v, "-");
            // 输出:1-2-3
            std::cout << s << std::endl;
        }
    
        {
            //Example 5:
            // Dereferencing of `std::unique_ptr<>` is also supported:
            std::vector<std::unique_ptr<int>> v;
            v.emplace_back(new int(1));
            v.emplace_back(new int(2));
            v.emplace_back(new int(3));
            std::string s = absl::StrJoin(v, "-");
            // 输出:1-2-3
            std::cout << s << std::endl;
        }
    
        {
            //Example 6:
            // Joins a `std::map`, with each key-value pair separated by an equals
            // sign. This pattern would also work with, say, a
            // `std::vector<std::pair<>>`.
            std::map<std::string, int> m = {
                std::make_pair("a", 1),
                std::make_pair("b", 2),
                std::make_pair("c", 3)};
            std::string s = absl::StrJoin(m, ",", absl::PairFormatter("="));
            // 输出:a=1,b=2,c=3
            std::cout << s << std::endl;
        }
    
        {
            //Example 7:
            // These examples show how `absl::StrJoin()` handles a few common edge
            // cases:
            std::vector<std::string> v_empty;
            // 输出:
            std::cout << absl::StrJoin(v_empty, "-") << std::endl;
    
            std::vector<std::string> v_one_item = {"foo"};
            // 输出:foo
            std::cout << absl::StrJoin(v_one_item, "-") << std::endl;
    
            std::vector<std::string> v_empty_string = {""};
            // 输出:
            std::cout << absl::StrJoin(v_empty_string, "-") << std::endl;
    
            std::vector<std::string> v_one_item_empty_string = {"a", ""};
            // 输出:a-
            std::cout << absl::StrJoin(v_one_item_empty_string, "-") << std::endl;
    
            std::vector<std::string> v_two_empty_string = {"", ""};
            // 输出:-
            std::cout << absl::StrJoin(v_two_empty_string, "-") << std::endl;
        }
    
        {
            //Example 8:
            // Joins a `std::tuple<T...>` of heterogeneous types, converting each to
            // a std::string using the `absl::AlphaNum` class.
            std::string s = absl::StrJoin(std::make_tuple(123, "abc", 0.456), "-");
            // 输出:123-abc-0.456
            std::cout << s << std::endl;
        }
    
        return 0;
    }
    
  • 格式字符串:absl::Substitute

    格式化字符串。Substitute使用一个格式字符串,该格式字符串包含由美元符号($)表示的位置标识符和单个数字位置标识符,以指示在格式字符串中的该位置使用哪个替换参数。使用时包含absl/strings/str_format.h。

    absl::Substitute与sprintf()有以下不同之处:

    • 不需要管理格式化缓冲区的内存。
    • 格式字符串不标识参数的类型。 相反,参数被隐式转换为字符串。
    • 格式字符串中的替换由’ $ '后跟一个数字标识。 可以乱序使用参数,并多次使用同一个参数。
    • 格式字符串中的’ $$ ‘序列意味着输出一个字面’ $ '字符。
    • absl::Substitute()明显比sprintf()快。 对于非常大的字符串,可能要快几个数量级。

    由于absl::Substitute()需要在运行时解析格式字符串,所以它比absl::StrCat()要慢。 只有当代码的清晰性比速度更重要时,才选择Substitute()而不是StrCat()。

    支持类型:

    • absl::string_view, std::string, const char* (null is equivalent to “”)
    • int32_t, int64_t, uint32_t, uint64_t
    • float, double
    • bool (Printed as “true” or “false”)
    • pointer types other than char* (Printed as 0x<lower case hex string>, except that null is printed as “NULL”)

    演示使用:

    std::string s = absl::Substitute("$1 purchased $0 $2. Thanks $1!", 5, "Bob", "Apples");
    // Produces the string "Bob purchased 5 Apples. Thanks Bob!"
    
    std::string s = "Hi. ";
    absl::SubstituteAndAppend(&s, "My name is $0 and I am $1 years old.", "Bob", 5);
    // Produces the string "Hi. My name is Bob and I am 5 years old."
    
  • 字符串匹配类

    使用时包含absl/strings/match.h。

    // Returns whether a given string `haystack` contains the substring `needle`.
    inline bool StrContains(absl::string_view haystack,
                            absl::string_view needle) noexcept;
    
    // Returns whether a given string `text` begins with `prefix`.
    inline bool StartsWith(absl::string_view text,
                           absl::string_view prefix) noexcept;
    
    // Returns whether a given string `text` ends with `suffix`.
    inline bool EndsWith(absl::string_view text,
                         absl::string_view suffix) noexcept;
    
    // Returns whether given ASCII strings `piece1` and `piece2` are equal, ignoring
    // case in the comparison.
    bool EqualsIgnoreCase(absl::string_view piece1,
                          absl::string_view piece2) noexcept;
    
    // Returns whether a given ASCII string `text` starts with `prefix`,
    // ignoring case in the comparison.
    bool StartsWithIgnoreCase(absl::string_view text,
                              absl::string_view prefix) noexcept;
    
    // Returns whether a given ASCII string `text` ends with `suffix`, ignoring
    // case in the comparison.
    bool EndsWithIgnoreCase(absl::string_view text,
                            absl::string_view suffix) noexcept;
    
  • 字符串替换:absl::StrReplaceAll

    使用时包含absl/strings/str_replace.h。

    std::string s = absl::StrReplaceAll(
                        "$who bought $count #Noun. Thanks $who!",
                        {{"$count", absl::StrCat(5)},
                         {"$who", "Bob"},
                         {"#Noun", "Apples"}});
    
  • 去掉固定字符串

    使用时包含absl/strings/strip.h。

    // 去掉字符串的固定字符的前缀
    bool ConsumePrefix(absl::string_view* str, absl::string_view expected);
    absl::string_view StripPrefix(absl::string_view str, absl::string_view prefix);
    
    // 去掉字符串的固定字符的后缀
    bool ConsumeSuffix(absl::string_view* str, absl::string_view expected);
    absl::string_view StripSuffix(absl::string_view str, absl::string_view suffix)
    
  • 字符串和数字之前的转换

    • 字符串转数字

      使用时包含absl/strings/numbers.h。

      absl::SimpleAtoi()将字符串转换为整型。

      absl::SimpleAtof()将字符串转换为浮点数。

      absl::SimpleAtod()将字符串转换为double类型。

      absl::SimpleAtob()将字符串转换为布尔值。

      absl::SimpleHexAtoi将十六进制字符串转换为整数。

    • 数字转字符串

      要将数值类型转换为字符串,请使用absl::StrCat()和absl::StrAppend()。 可以使用StrCat/StrAppend将int32、uint32、int64、uint64、float和double类型转换为字符串。

  • 内存缓冲区: absl::CordBuffer

    CordBuffer为一些目的管理内存缓冲区,例如零复制api,以及构建大数据连接的应用程序,这些应用程序需要对连接数据的分配和大小进行细粒度控制。使用时包含absl/strings/cord_buffer.h。

  • 字符串序列:absl::Cord

    Cord是一个字符序列,在某些情况下设计成比’ std::string '更高效:也就是说,需要在其生命周期内更改或共享的大型字符串数据,特别是当这些数据跨API边界共享时。

  • 字符串格式化: absl::str_format

    str_format库是标准库标头中的printf()字符串格式化例程的类型安全替代品。 str_format库提供了printf()类型字符串格式化的大部分功能和一些额外的好处:

    • 类型安全,包括对std::string和absl::string_view的本机支持

    • 独立于标准库的可靠行为

    • 支持POSIX位置扩展

    • 本机支持Abseil类型,如absl::Cord,并可扩展以支持其他类型。

    • 比本机printf函数快得多(通常快2到3倍)

    • 可流化到各种现有的接收器

    • 可扩展到自定义接收器

  • 其他关于字符的工具库

    详细可以参看absl/strings/ascii.h

    // `ascii_isalnum()`, `ascii_isalpha()`, `ascii_isascii()`, `ascii_isblank()`,
    // `ascii_iscntrl()`, `ascii_isdigit()`, `ascii_isgraph()`, `ascii_islower()`,
    // `ascii_isprint()`, `ascii_ispunct()`, `ascii_isspace()`, `ascii_isupper()`,
    // `ascii_isxdigit()`
    
    // `ascii_tolower()`, `ascii_toupper()`
    
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xiaobaiPlayGame

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值