一、标准库中的字符串类型
在C++中,字符串是一个非常重要的数据类型,用于表示和处理文本信息。C++提供了多种方式来处理字符串,每种方式都有其特点和适用场景。以下是几种常见的字符串类型及其用法:
1. C 风格字符串 (char*
或 char[]
)
C 风格字符串是最基础的字符串表示方式,它是一个以空字符 \0
结尾的字符数组。
char str1[] = "Hello, World!";
char* str2 = "Hello, World!";
特点:
- 直接使用字符数组,简单高效。
- 没有内置的长度检查,容易发生缓冲区溢出等问题。
- 需要手动管理内存。
示例:
#include <iostream>
#include <cstring> // for strlen, strcpy, etc.
int main() {
char str1[] = "Hello, World!";
char str2[50];
std::cout << "Length of str1: " << strlen(str1) << std::endl;
strcpy(str2, str1); // Copy str1 to str2
std::cout << "str2: " << str2 << std::endl;
return 0;
}
2. std::string
(C++ 标准库)
C++标准库中的<string>
头文件定义了std::string
类,提供了丰富的成员函数和操作符重载,使得字符串处理更加方便和安全。
#include <string>
#include <iostream>
int main() {
std::string str1 = "Hello, World!";
std::string str2 = str1 + " How are you?";
std::cout << "str1: " << str1 << std::endl;
std::cout << "str2: " << str2 << std::endl;
std::cout << "Length of str2: " << str2.length() << std::endl;
return 0;
}
特点:
- 类型安全:避免缓冲区溢出等安全问题。
- 动态管理内存,不需要手动释放。
- 提供了丰富的成员函数,如
length()
,substr()
,find()
,replace()
等。 - 支持字符串拼接、比较等操作。
- 支持移动语义,允许更高效地处理临时字符串。
- 可以从其他字符串、字符数组、字符指针以及初始化列表构造字符串。
- C++ 新增成员函数
-
`shrink_to_fit()`:减少内存使用,将容量减少到与大小相同。
-
`to_string()`:将数值类型转换为字符串。
-
`stoi()`, `stol()`, `stoll()`, `stof()`, `stod()`, `stold()`:字符串到数值的转换函数。
3. 字符串字面量
C++ 11引入了原始字符串字面量,它允许字符串字面量包含任意字符,包括换行符、制表符和引号,而不需要进行转义。原始字符串字面量以 R"(...)"
的形式书写,例如:
const char* raw_str = R"(Hello "World"
This is a raw string literal)";
4. 宽字符字符串1 wchar_t*
或 wchar_t[]
宽字符字符串用于处理多字节字符集,如 Unicode。它们使用 wchar_t
类型来存储字符。
wchar_t wstr1[] = L"Hello, World!";
wchar_t* wstr2 = L"Hello, World!";
特点:
- 每个字符占用多个字节,适合处理多字节字符集。
- 使用
wchar_t
类型,需要特殊的函数来处理,如wcslen
,wcscpy
等。
示例:
#include <iostream>
#include <cwchar> // for wcslen, wcscpy, etc.
int main() {
wchar_t wstr1[] = L"Hello, World!";
wchar_t wstr2[50];
std::wcout << L"Length of wstr1: " << wcslen(wstr1) << std::endl;
wcscpy(wstr2, wstr1); // Copy wstr1 to wstr2
std::wcout << L"wstr2: " << wstr2 << std::endl;
return 0;
}
5. 宽字符字符串2 std::wstring
std::wstring
是 std::string
的宽字符版本,用于处理宽字符字符串。
#include <string>
#include <iostream>
int main() {
std::wstring wstr1 = L"Hello, World!";
std::wstring wstr2 = wstr1 + L" How are you?";
std::wcout << L"wstr1: " << wstr1 << std::endl;
std::wcout << L"wstr2: " << wstr2 << std::endl;
std::wcout << L"Length of wstr2: " << wstr2.length() << std::endl;
return 0;
}
Unicode 字符串字面量
C++ 11支持Unicode字符串字面量,允许使用 Unicode 字符集编写字符串字面量。可以使用 u8
前缀表示UTF-8编码,u
前缀表示UTF-16编码,U
前缀表示UTF-32编码。例如:
const char* utf8_str = u8"Hello, 世界"; // UTF-8
const char16_t* utf16_str = u"Hello, 世界"; // UTF-16
const char32_t* utf32_str = U"Hello, 世界"; // UTF-32
特点:
- 动态管理内存,不需要手动释放。
- 提供了丰富的成员函数,如
length()
,substr()
,find()
,replace()
等。 - 支持宽字符字符串的拼接、比较等操作。
6. std::u16string
和 std::u32string
从 C++11 开始,标准库引入了 std::u16string
和 std::u32string
,分别用于处理 16 位和 32 位的 Unicode 字符串。
#include <string>
#include <iostream>
int main() {
std::u16string u16str1 = u"Hello, World!";
std::u32string u32str1 = U"Hello, World!";
std::cout << "u16str1: " << std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>().to_bytes(u16str1) << std::endl;
std::cout << "u32str1: " << std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t>().to_bytes(u32str1) << std::endl;
return 0;
}
特点:
- 分别使用
char16_t
和char32_t
类型来存储字符。 - 适用于处理 UTF-16 和 UTF-32 编码的字符串。
- 需要使用
std::wstring_convert
进行编码转换。
总结
- C 风格字符串:简单高效,但容易出错。
std::string
:功能丰富,使用方便,安全性高。- 宽字符字符串:适用于多字节字符集,如 Unicode。
std::wstring
:std::string
的宽字符版本。std::u16string
和std::u32string
:适用于 UTF-16 和 UTF-32 编码的字符串。
选择合适的字符串类型取决于你的具体需求,例如是否需要处理多字节字符集、是否需要更高的安全性等。
二、 常用字符串操作
以下是一些常用的字符串操作:
-
构造和赋值:
std::string str1 = "Hello"; std::string str2(str1); // 拷贝构造 std::string str3 = str1 + ", World!"; // 字符串连接
-
长度和容量:
size_t length = str.length(); // 或 str.size() size_t capacity = str.capacity();
-
修改字符串:
str.append("append this"); // 在末尾添加字符串 str.insert(7, "inserted "); // 在指定位置插入字符串 str.erase(5, 3); // 删除指定位置的字符 str.replace(5, 3, "replaced"); // 替换指定位置的字符
-
查找和比较:
size_t found = str.find("World"); // 查找子串 bool equal = (str1 == str2); // 比较字符串
-
子串提取:
std::string substr = str.substr(7, 5); // 提取子串
-
字符访问:
std::string str = "Hello, World!"; // 通过索引访问字符串中的字符 for (size_t i = 0; i < str.size(); ++i) { std::cout << "Character at index " << i << " is: " << str[i] << std::endl; }
-
字符串流:
C++还提供了字符串流(std::istringstream
、std::ostringstream
、std::stringstream
),可以用于字符串的格式化输入输出操作。
#include <sstream>
std::ostringstream oss;
oss << "Hello" << ", " << "World!";
std::string formatted_str = oss.str();
这些是C++中处理字符串的基本方式。在实际编程中,std::string
因其易用性和安全性而成为处理字符串的首选方式。
std::getline
的增强
std::getline
函数现在可以接受任何输入流和字符串,而不仅仅是 std::string
。这使得从流中读取数据更加灵活。
正则表达式库
C++ 11引入了 <regex>
库,它提供了一种使用正则表达式处理字符串的方式。这个库包括正则表达式类型 std::regex
和用于匹配、查找和替换的函数。
自动类型推导
C++ 11引入了 auto
关键字,可以用于自动推导变量的类型,这在处理字符串迭代器时非常有用,因为它们通常很长且难以记忆。
for (auto it = str.begin(); it != str.end(); ++it) {
// 使用迭代器
}
以上是C++ 11中字符串相关的一些主要特性。这些特性极大地提高了字符串处理的灵活性和便利性,使得C++在文本处理方面的能力得到了显著增强。
std::string
的编码格式
std::string
是 C++ 标准库中的一个类,用于表示和处理字符串。在 std::string
中,字符串的编码格式并不是由 std::string
类本身决定的,而是由字符串中存储的数据和程序解释这些数据的方式决定的。
以下是一些关于 std::string
编码格式的要点:
- 字符类型:
std::string
存储的是一系列字符,这些字符默认是char
类型。在大多数系统上,char
是一个字节(8位),并且可以用来存储 ASCII 编码的字符。 - ASCII 编码:如果
std::string
仅包含 ASCII 字符(即字符值在 0 到 127 之间),则它通常被解释为 ASCII 编码。ASCII 是一个单字节编码方案,能够表示英文字母、数字和一些特殊符号。 - 扩展 ASCII 编码:有时
std::string
可能包含扩展 ASCII 字符(字符值在 128 到 255 之间),这取决于系统的本地编码设置。扩展 ASCII 允许表示更多的字符,例如重音符号和其他语言的一些字符。 - 多字节编码:如果
std::string
用于表示非 ASCII 字符,如 Unicode 字符,那么字符串可能使用多字节编码方案,如 UTF-8、UTF-16 或 UTF-32。在这些编码方案中,不同的字符可能占用不同数量的字节。- UTF-8:是一种变长编码,使用 1 到 4 个字节表示一个 Unicode 字符。它是网络传输中最常用的编码格式,并且与 ASCII 编码向后兼容。
- UTF-16:是另一种变长编码,使用 2 或 4 个字节表示一个 Unicode 字符。
- UTF-32:使用固定 4 个字节表示一个 Unicode 字符。
- 编码的独立性:
std::string
类本身并不关心字符串内部的编码格式。当你在std::string
中存储字符时,它仅仅是将这些字符作为字节序列来处理。因此,如果需要处理特定的编码格式,程序员需要确保正确地编码和解码字符串。 - 编码转换:在实际应用中,你可能需要将
std::string
从一种编码转换为另一种编码。这通常需要使用专门的库,如 ICU(International Components for Unicode)或者 C++11 以后的标准库中的<codecvt>
头文件(尽管<codecvt>
在 C++17 中已被弃用)。 - 字符串字面量:在 C++ 中,字符串字面量(如
"Hello, World!"
)默认是 ASCII 编码的。但是,C++11 引入了 Unicode 字符串字面量,允许使用前缀u
(UTF-16)、U
(UTF-32)和u8
(UTF-8)来表示不同编码的字符串。
总之,std::string
的编码格式取决于你的程序如何解释存储在其中的字节序列,而std::string
类本身并不强制或假设任何特定的编码。