std::string 类是一个连续容器,类似于 vector 或数组。它支持 contiguous_iterator 概念以及所有相应的算法。
string 类是 basic_string 的一个特化版本,其类型为 char。这意味着容器的元素类型为 char。还有其他特化版本可用,但 string 是最常见的。
由于它本质上是一个 char 元素的连续容器,因此可以使用 transform() 算法或任何使用 contiguous_iterator 概念的其他技术对 string 进行操作。
如何做……
根据应用程序的不同,有多种转换方法。本示例将探讨其中的几种。
我们将从几个谓词函数开始。谓词函数接受一个转换元素并返回一个相关元素。例如,下面是一个简单的谓词函数,它返回一个大写字符:
char char_upper(const char& c) {
return static_cast<char>(std::toupper(c));
}
这个函数是 std::toupper() 的一个包装器。由于 toupper() 函数返回一个 int,而 string 的元素类型是 char,因此我们不能直接在转换中使用 toupper() 函数。
下面是相应的 char_lower() 函数:
char char_lower(const char& c) {
return static_cast<char>(std::tolower(c));
}
rot13() 函数是一个有趣的转换谓词,用于演示目的。它是一个简单的替换密码,不适合加密,但常用于混淆:
char rot13(const char& x) {
auto rot13a = [](char x, char a)->char {
return a + (x - a + 13) % 26;
};
if (x >= 'A' && x <= 'Z') return rot13a(x, 'A');
if (x >= 'a' && x <= 'z') return rot13a(x, 'a');
return x;
}
我们可以使用这些谓词函数与 transform() 算法:
int main() {
string s{ "hello jimi\n" };
cout << s;
std::transform(s.begin(), s.end(), s.begin(), char_upper);
cout << s;
// ...
transform() 函数对 s 中的每个元素调用 char_upper(),将结果放回 s 中,并将所有字符转换为大写:
输出:
hello jimi
HELLO JIMI
除了 transform() 之外,我们还可以使用带有谓词函数的简单 for 循环:
for(auto& c : s) c = rot13(c);
cout << s;
从我们的大写字符串对象开始,结果是:
URYYB WVZV
rot13 密码的一个有趣之处在于它可以自我解密。因为 ASCII 字母表中有 26 个字母,旋转 13 次后再旋转 13 次将得到原始字符串。让我们将其转换为小写并再次使用 rot13 来恢复字符串:
for(auto& c : s) c = rot13(char_lower(c));
cout << s;
输出:
hello jimi
由于它们的统一接口,谓词函数可以作为彼此的参数进行链接。我们还可以使用 char_lower(rot13(c)) 来获得相同的结果。
如果你的需求对于简单的逐个字符转换来说太复杂,你可以像使用任何连续容器一样使用 string 迭代器。下面是一个简单的函数,它将小写字符串转换为标题大小写(Title Case),即将第一个字符和每个空格后面的字符转换为大写:
string& title_case(string& s) {
auto begin = s.begin();
auto end = s.end();
*begin++ = char_upper(*begin); // 第一个元素
bool space_flag{ false };
for(auto it{ begin }; it != end; ++it) {
if(*it == ' ') {
space_flag = true;
} else {
if(space_flag) *it = char_upper(*it);
space_flag = false;
}
}
return s;
}
由于它返回转换后字符串的引用,我们可以像这样使用 cout 调用它:
cout << title_case(s);
输出:
Hello Jimi
工作原理……
std::basic_string 类及其特化版本(包括 string)受迭代器支持,这些迭代器完全符合 contiguous_iterator。这意味着任何适用于任何连续容器的技术也适用于 string。
注意:
由于底层数据是 const-qualified,这些转换不适用于 string_view 对象。