ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

absl教程(四):Strings Library

2021-09-21 16:02:23  阅读:1494  来源: 互联网

标签:std string Library 字符串 StrSplit absl Strings view


absl/strings库提供了用于操作和比较字符串、将其他类型(例如整数)转换为字符串或为其他用途评估字符串的类和实用程序函数。此外,该 strings库还包含用于将数据存储在连续内存中的“类字符串”类的实用程序函数。

本文档概述了strings 库的亮点和一般用例。有关特定类、函数和字段的更多详细信息,请参阅特定头文件中的源文档。

尽管“字符串”通常被认为是 C++ 中的标准类型,但它们并不是内置类型,而是通过std::string类在标准库中提供 。从根本上说,一个字符串由一个大小和一个char字符数组组成 。

absl::string_view集装箱

通常,您需要访问字符串数据,但您不需要拥有它,也不需要修改它。出于这个原因,Abseil 定义了一个 absl::string_view类,它指向一个连续的字符范围,通常是另一个std::string双引号字符串文字、字符数组甚至另一个 的一部分或全部string_view。A string_view,顾名思义,提供其关联字符串数据的只读视图。

大多数 C++ 代码历来使用(较旧的)Cchar*指针类型或 C++std::string类来保存字符数据。希望使用这两种类型数据的方法如果想要避免复制数据,通常需要提供重载实现。Astring_view还充当接受两种类型字符数据的 API 的包装器;方法可以简单地声明它们接受absl::string_view

// A common use of string_view: Foo() can accept both char* and std::string via
// implicit conversion to string_view.
void Foo(absl::string_view s) { ... }

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

如上所述,因为string_view本身不拥有底层数据,所以它应该只用于只读数据。如果您需要向外部 API 用户提供字符串常量,例如:

// C++17: A read-only string in a header file.
inline constexpr absl::string_view kGreeting = "hi";
// C++11: A read-only string in a header file. Due to lifetime issues, a
// string_view is usually a poor choice for a return value (see below), but it's
// safe here because the static storage outlives it.
inline absl::string_view GetGreeting() {
  static constexpr char kGreeting[] = "hi";
  return kGreeting;
}

string_view如果您知道底层对象的生命周期长于string_view变量的生命周期,A也适用于局部 变量。但是,请注意将其绑定到临时值:

// BAD use of string_view: lifetime problem
absl::string_view sv = obj.ReturnAString();

// GOOD use of string_view: str outlives sv
std::string str = obj.ReturnAString();
absl::string_view sv = str;

由于生命周期问题,string_view对于返回值来说 a 通常是一个糟糕的选择,对于数据成员来说几乎总是一个糟糕的选择。如果您确实以这种方式使用了一个,则您有责任确保string_view不会超过它指向的对象。

Astring_view可以代表整个字符串或只是字符串的一部分。例如,拆分字符串时,std::vector<absl::string_view>是输出的自然数据类型。

注意:有关 的更多信息string_view,请参阅 abseil.io/tips/1

注意:有关常量的安全习语的更多信息,请参阅 abseil.io/tips/140

absl::StrSplit() 用于拆分字符串

absl::StrSplit()函数提供了一种将字符串拆分为子字符串的简单方法。StrSplit()接受要分割的输入字符串、分割字符串的定界符(例如逗号,)和(可选)作为过滤器的谓词,以判断是否将分割元素包含在结果集中。 StrSplit()还将返回的集合调整为调用者指定的类型。

例子:

// Splits the given string on commas. Returns the results in a
// vector of strings. (Data is copied once.)
std::vector<std::string> v = absl::StrSplit("a,b,c", ',');  // Can also use ","
// v[0] == "a", v[1] == "b", v[2] == "c"

// Splits the string as in the previous example, except that the results
// are returned as `absl::string_view` objects, avoiding copies. Note that
// because we are storing the results within `absl::string_view` objects, we
// have to ensure that the input string outlives any results.
std::vector<absl::string_view> v = absl::StrSplit("a,b,c", ',');
// v[0] == "a", v[1] == "b", v[2] == "c"

StrSplit()使用传递的Delimiter对象拆分字符串。(请参阅 下面的分隔符。)但是,在许多情况下,您可以简单地将字符串文字作为分隔符传递(它将被隐式转换为 absl::ByString分隔符)。

例子:

// By default, empty strings are *included* in the output. See the
// `absl::SkipEmpty()` predicate below to omit them{#stringSplitting}.
std::vector<std::string> v = absl::StrSplit("a,b,,c", ',');
// v[0] == "a", v[1] == "b", v[2] == "", v[3] = "c"

// You can also split an empty string
v = absl::StrSplit("", ',');
// v[0] = ""

// The delimiter need not be a single character
std::vector<std::string> v = absl::StrSplit("aCOMMAbCOMMAc", "COMMA");
// v[0] == "a", v[1] == "b", v[2] == "c"

// You can also use the empty string as the delimiter, which will split
// a string into its constituent characters.
std::vector<std::string> v = absl::StrSplit("abcd", "");
// v[0] == "a", v[1] == "b", v[2] == "c", v[3] = "d"

适应返回类型

StrSplit()API更有用的特性之一是它能够将其结果集调整为所需的返回类型。StrSplit()返回的集合可能包含std::stringabsl::string_view或任何可以从absl::string_view. 这种模式适用于所有的标准STL容器,包括std::vectorstd::liststd::dequestd::setstd::multisetstd::map,和std::multimap,甚至std::pair,这是不实际的容器。

例子:

// Stores results in a std::set<std::string>, which also performs de-duplication
// and orders the elements in ascending order.
std::set<std::string> s = absl::StrSplit("b,a,c,a,b", ',');
// s[0] == "a", s[1] == "b", s[3] == "c"

// Stores results in a map. The map implementation assumes that the input
// is provided as a series of key/value pairs. For example, the 0th element
// resulting from the split will be stored as a key to the 1st element. If
// an odd number of elements are resolved, the last element is paired with
// a default-constructed value (e.g., empty string).
std::map<std::string, std::string> m = absl::StrSplit("a,b,c", ',');
// m["a"] == "b", m["c"] == "" // last component value equals ""

// Stores first two split strings as the members in a std::pair. Any split
// strings beyond the first two are omitted because std::pair can hold only two
// elements.
std::pair<std::string, std::string> p = absl::StrSplit("a,b,c", ',');
// p.first = "a", p.second = "b" ; "c" is omitted

分隔符

StrSplit()API提供了许多“分隔符”,用于提供特殊的分隔符的行为。Delimiter 实现包含一个Find()函数,该函数知道如何在给定的absl::string_view. Delimiter 概念的模型表示特定类型的分隔符,例如单个字符、子字符串,甚至正则表达式。

以下 Delimiter 抽象作为StrSplit() API 的一部分提供:

  • absl::ByString()std::string参数的默认值)
  • absl::ByChar()char参数的默认值)
  • absl::ByAnyChar() (用于混合分隔符)
  • absl::ByLength() (用于应用定界符一定次数)
  • absl::MaxSplits() (用于拆分特定次数)

例子:

// Because a `string` literal is converted to an `absl::ByString`, the following
// two splits are equivalent.
std::vector<std::string> v = absl::StrSplit("a,b,c", ",");
std::vector<std::string> v = absl::StrSplit("a,b,c", absl::ByString(","));
// v[0] == "a", v[1] == "b", v[2] == "c"

// Because a `char` literal is converted to an `absl::ByChar`, the following two
// splits are equivalent.
std::vector<std::string> v = absl::StrSplit("a,b,c", ',');
// v[0] == "a", v[1] == "b", v[2] == "c"

std::vector<std::string> v = absl::StrSplit("a,b,c", absl::ByChar(','));
// v[0] == "a", v[1] == "b", v[2] == "c"

// Splits on any of the given characters ("," or ";")
vector<std::string> v = absl::StrSplit("a,b;c", absl::ByAnyChar(",;"));
// v[0] == "a", v[1] == "b", v[2] == "c"

// Uses the `absl::MaxSplits` delimiter to limit the number of matches a
// delimiter can have. In this case, the delimiter of a literal comma is limited
// to matching at most one time. The last element in the returned collection
// will contain all unsplit pieces, which may contain instances of the
// delimiter.
std::vector<std::string> v = absl::StrSplit("a,b,c", absl::MaxSplits(',', 1));
// v[0] == "a", v[1] == "b,c"

// Splits into equal-length substrings.
std::vector<std::string> v = absl::StrSplit("12345", absl::ByLength(2));
// v[0] == "12", v[1] == "34", v[2] == "5"

过滤谓词

谓词可以StrSplit()通过确定结果元素是否包含在结果集中来过滤操作的结果。过滤谓词可以作为可选的第三个参数传递给StrSplit() 函数。

谓词必须是一元函数(或函子),它们接受单个 absl::string_view参数并返回一个布尔值,指示该参数是应该被包含 ( true) 还是排除 ( false)。

一个使用谓词很有用的例子:过滤掉空子串。默认情况下,空子字符串可以StrSplit()作为结果集中的单独元素返回,这类似于其他编程语言中拆分函数的工作方式。

// Empty strings *are* included in the returned collection.
std::vector<std::string> v = absl::StrSplit(",a,,b,", ',');
// v[0] == "", v[1] == "a", v[2] == "", v[3] = "b", v[4] = ""

这些空字符串可以通过简单地将提供的SkipEmpty()谓词作为第三个参数传递给StrSplit() 函数来从结果集中过滤掉。SkipEmpty()不认为包含所有空格的字符串为空。对于该行为,请使用SkipWhitespace()谓词。

例子:

// Uses absl::SkipEmpty() to omit empty strings. Strings containing whitespace
// are not empty and are therefore not skipped.
std::vector<std::string> v = absl::StrSplit(",a, ,b,", ',', absl::SkipEmpty());
// v[0] == "a", v[1] == " ", v[2] == "b"

// Uses absl::SkipWhitespace() to skip all strings that are either empty or
// contain only whitespace.
std::vector<std::string> v = absl::StrSplit(",a, ,b,", ',',
                                            absl::SkipWhitespace());
// v[0] == "a", v[1] == "b"

absl::StrCat()absl::StrAppend()字符串连接

大多数关于 C++ 字符串使用的文档都提到,与其他语言不同,C++ 中的字符串是可变的;但是,修改字符串的成本可能很高,因为字符串通常包含大量数据,而且许多模式都涉及创建临时副本,这可能会产生大量开销。始终寻找减少创建此类临时对象的方法。

例如,以下代码效率低下:

// Inefficient code
std::string s1 = "A string";
s1 = s1 + " another string";

上面的赋值运算符创建一个临时字符串,复制s1到该临时字符串中,连接该临时字符串,然后将其分配回s1. 而是使用优化的+=运算符进行此类连接:

// Efficient code
s1 += " another string";

好的编译器或许能够优化前面的低效代码。但是,涉及多个串联的操作通常无法避免临时性:

// Inefficient code
std::string s1 = "A string";
std::string another = " and another string";
s1 += " and some other string" + another;

出于这个原因,Abseil 提供了absl::StrCat()absl::StrAppend() 函数来有效地连接和附加字符串。absl::StrCat() 并且absl::StrAppend()通常比诸如 之类的运算符更有效+=,因为它们不需要创建临时std::string对象,并且它们的内存在字符串构造期间预先分配。

// Inefficient code
std::string s1 = "A string";
std::string another = " and another string";
s1 += " and some other string" + another;

// Efficient code
std::string s1 = "A string";
std::string another = " and another string";
absl::StrAppend(&s1, " and some other string", another);

出于这个原因,您应该养成优先使用absl::StrCat()absl::StrAppend()不使用连接运算符的习惯。

absl::StrCat()

absl::StrCat()将任意数量的字符串或数字合并为一个字符串,旨在成为从原始 C 字符串、absl::string_view元素、std::string值以及布尔值和数字值的混合中构造字符串的最快方法。StrCat()通常在涉及多个二元运算符(例如a + b + c或 )的 字符串连接时更有效a += b + c,因为它们避免在字符串构造期间创建临时字符串对象。

// absl::StrCat() can merge an arbitrary number of strings
std::string s1;
s1 = absl::StrCat("A string ", " another string", "yet another string");

// StrCat() also can mix types, including std::string, string_view, literals,
// and more.
std::string s1;
std::string s2 = "Foo";
absl::string_view sv1 = MyFunction();
s1 = absl::StrCat(s2, sv1, "a literal");

StrCat() 为以下类型提供自动格式化:

  • std::string
  • absl::string_view
  • 字符串文字
  • 数值(浮点数、整数)
  • 布尔值(转换为“0”或“1”)
  • 通过使用absl::Hex()转换函数的十六进制值

浮点值使用与 STL 的 std::basic_ostream::operator« 相同的格式转换为字符串,即 6 位精度,当大小小于 0.001 或大于等于 1e+ 时使用“e”格式6.

您可以使用absl::Hex类型转换为十六进制输出而不是十进制输出 。为此,请将其Hex(my_int)作为参数传递给StrCat()or StrAppend()。你可能宽度使用指定最小六角字段 absl::PadSpec枚举,所以等效的StringPrintf("%04x", my_int)absl::StrCat(absl::Hex(my_int, absl::kZeroPad4))

absl::StrAppend()

为了清晰和性能,absl::StrCat()在附加到字符串时不要使用。使用absl::StrAppend()来代替。特别是,避免使用以下任何(反)模式:

str.append(absl::StrCat(...))
str += absl::StrCat(...)
str = absl::StrCat(str, ...)

absl::StrJoin() 用于连接字符串中的元素

虽然类似于absl::StrCat()一些类似的用例,但 absl::StrJoin()提供了更强大的实用程序,用于连接一系列元素、定义分隔符字符串以及将结果格式化为字符串。

范围通过使容器与指定的std::begin()std::end() 迭代器,容器特异性begin()end()迭代器,一个支架初始化std::initializer_list,或std::tuple异质的对象。分隔符字符串指定为absl::string_view.

因为默认格式化程序使用absl::AlphaNum类, absl::StrJoin()absl::StrCat(),将在字符串、整数、浮点数、双精度数等集合上开箱即用。

例子

std::vector<std::string> v = {"foo", "bar", "baz"};
std::string s = absl::StrJoin(v, "-");
// Produces the string "foo-bar-baz"

// 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"}, "-");
// Produces the string "foo-bar-baz"

// Joins a collection of ints. This pattern also works with floats,
// doubles, int64s -- any `absl::StrCat()`-compatible type.
std::vector<int> v = {1, 2, 3, -4};
std::string s = absl::StrJoin(v, "-");
// Produces the string "1-2-3--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, "-");
// Produces the string "1-2-3"

// Dereferencing of `std::unique_ptr<>` is also supported:
std::vector<std::unique_ptr<int>> v
v.push_back(absl::make_unique<int>(1));
v.push_back(absl::make_unique<int>(2));
v.push_back(absl::make_unique<int>(3));
std::string s = absl::StrJoin(v, "-");
// Produces the string "1-2-3"

// 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 = {{"a", 1}, {"b", 2}, {"c", 3}};
std::string s = absl::StrJoin(m, ",", absl::PairFormatter("="));
// Produces the string "a=1,b=2,c=3"

加入格式化程序

absl::StrJoin()使用“格式化程序”来格式化要加入的元素(AlphaNumFormatter()如果没有指定格式化程序,则默认为。格式化程序是一个函数对象,负责将其参数格式化为字符串并将其附加到给定的输出字符串。格式化程序可能是实现为函数对象、lambdas 或普通函数。您可以提供自己的 Formatter 以启用absl::StrJoin()任意类型。

以下是一个自定义 Formatter 的示例,它仅用于 std::to_string()将整数格式化为字符串:

struct MyFormatter {
  void operator()(std::string* out, int i) const {
    out->append(std::to_string(i));
  }
};

您可以通过将其实例作为最终参数传递给上述格式化程序来使用absl::StrJoin()

std::vector<int> v = {1, 2, 3, 4};
std::string s = absl::StrJoin(v, "-", MyFormatter());
// Produces the string "1-2-3-4"

StrJoin()API中提供了以下标准格式化程序:

  • AlphaNumFormatter() (默认)
  • StreamFormatter() 使用 « 运算符格式化其参数。
  • PairFormatter()``std::pair通过在对的.first.second成员之间放置一个给定的分隔符来格式化 a 。
  • DereferenceFormatter()通过取消引用它然后应用给定的格式化程序来格式化它的参数。此格式化程序可用于格式化指向 T 的指针的容器。当在协议缓冲区中加入重复的字段时,经常会出现这种模式。

absl::Substitute() 用于字符串替换

格式化字符串以显示给用户通常有不同的需求。传统上,大多数 C++ 代码使用内置函数,例如sprintf()snprintf();这些函数有一些问题,它们不支持 absl::string_view并且必须管理格式化缓冲区的内存。

// Bad. Need to worry about buffer size and NUL-terminations.

std::string GetErrorMessage(char *op, char *user, int id) {
  char buffer[50];
  sprintf(buffer, "Error in %s for user %s (id %i)", op, user, id);
  return buffer;
}

// Better. Using absl::StrCat() avoids the pitfalls of sprintf() and is faster.
std::string GetErrorMessage(absl::string_view op, absl::string_view user, int id) {
  return absl::StrCat("Error in ", op, " for user ", user, " (", id, ")");
}

// Best. Using absl::Substitute() is easier to read and to understand.
std::string GetErrorMessage(absl::string_view op, absl::string_view user, int id) {
  return absl::Substitute("Error in $0 for user $1 ($2)", op, user, id);
}

absl::Substitute()结合的效率和类型安全性质 absl::StrCat()中包含的常规功能参数结合 sprintf()absl::Substitute使用包含由美元符号 ($) 指示的位置标识符和单个数字位置 ID 的格式字符串来指示在格式字符串中的该位置使用哪些替换参数。

std::string s = Substitute("$1 purchased $0 $2. Thanks $1!", 5, "Bob", "Apples");
// Produces the string "Bob purchased 5 Apples. Thanks Bob!"

std::string s = "Hi. ";
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::Substitute(),因为它需要在运行时解析格式字符串,所以 比absl::StrCat(). 选择Substitute()StrCat()只有当代码清晰比速度更重要。

StringPrintf()

absl::SubstituteStringPrintf()以下方面不同:

  • 格式字符串不标识参数的类型。相反,参数被隐式转换为字符串。
  • 格式字符串中的替换由后跟单个数字的“$”标识。您可以乱序使用参数并多次使用相同的参数。
  • 格式字符串中的 ‘$ ′ 序 列 意 味 着 输 出 文 字 ′ ' 序列意味着输出文字 ' ′序列意味着输出文字′’ 字符。
  • absl::Substitute()明显快于StringPrintf(). 对于非常大的字符串,它可能会快几个数量级。

支持的类型

absl::Substitute() 了解以下类型:

  • absl::string_view, std::string, const char*(null 等价于“”)
  • int32_t, int64_t, uint32_t,uint64_t
  • float, double
  • bool (打印为“真”或“假”)
  • char* 以外的指针类型(打印为0x<lower case hex string>,除了 null 打印为“NULL”)

absl::StrContains() 用于字符串匹配

Abseil 字符串库还包含用于执行字符串匹配检查的简单实用程序。他们所有的函数的参数被指定为 absl::string_view,这意味着这些功能都可以接受std::stringabsl::string_view或NULL结尾的C风格的字符串。

// Assume "msg" is a line from a logs entry
if (absl::StrContains(msg, "ERROR")) {
  *has_error = true;
}
if (absl::StrContains(msg, "WARNING")) {
  *has_warning = true;
}

注意:这些函数中参数的顺序旨在模仿等效成员函数的顺序;例如s.Contains(x)==> absl::StrContains(s, x)

与数字类型相互转换

absl/strings库中将字符串转换为数字类型的特殊函数 在numbers.h中定义 。以下功能特别有用:

  • absl::SimpleAtoi() 将字符串转换为整数类型。
  • absl::SimpleAtof() 将字符串转换为浮点数。
  • absl::SimpleAtod() 将字符串转换为双精度。
  • absl::SimpleAtob() 将字符串转换为布尔值。

要将数字类型转换为字符串,请使用absl::StrCat()absl::StrAppend()。您可以使用StrCat/StrAppend转换int32uint32int64uint64float,和double类型为字符串:

std::string foo = StrCat("The total is ", cost + tax + shipping);

标签:std,string,Library,字符串,StrSplit,absl,Strings,view
来源: https://blog.csdn.net/yao_hou/article/details/120402293

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有