C++中如何处理中文字符。学过C++的都知道标准库中的 std::string更像是一个存储着 char的容器,而不是普遍意义上的字符串。而我们的中文字符又无法使用单个 char进行存储。
常见用于中文的的字符编码有 GBK和 UTF-8,UTF-16等,在Windows中文操作系统中,默认字符编码是 GBK使用2个字节存储一个中文字符;而在Linux以及macOS中使用 UTF-8编码。UTF-8编码是一个变长的编码:一个ASCIl字符只需1字节编码;带有变音符号的其他语言文字的字母需要2字节编码;中文以及日韩等一些亚洲文字需要3个字节编码;其他一些极少使用的字符使用4个字节编码。
那C++中的 std::string采用什么编码呢?一般来说,在Windows中文环境下,C++源文件的编码通常为GBK; 在Linux及macOS环境下,默认的为UTF-8 编码。在不依赖第三方库处理C++字符串时,一般可以使用 std::string进行读写,输入和输出;当要进行中文处理的时候,将其转为 std::wstring进行。当然,如果你需要进行复杂的字符串处理,可以通过第三方库例如,ICU、Qt、Poco等,这些第三方库提供了很多强大的功能。
下面程序演示了如何进行两者的转化,最后将转换后的 std::wstring使用空格进行分割输出(程序在macOS上运行通过,在Windows下可能还需要额外工作)。
// 中文字符串使用
#include <string>
#include <codecvt>
#include <print>
#include <ranges>
#include <vector>
#include <algorithm>
#include <iostream>
export module CString;
using std::print;
using std::println;
using std::string;
using std::wstring;
using std::vector;
export class Solution {
public:
static void run() {
// 定义一个普通字符串,使用现代C++的println函数进行输出
const string s = "你好 Jay Chou";
println("采用std::string存储的「{}」的长度为{}", s, s.length());
// 将string转为wstring,这里的codecvt_utf8对象用于将UTF-8编码的字符串转为宽字符串
std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
const wstring ws = converter.from_bytes(s.data());
// 由于println函数不支持wstring的输出,这里输出仍然采用char存储的字符串
println("采用std::wstring存储的「{}」的长度为{}", s, ws.length());
// 将本地编码支持设置为系统环境变量默认编码
std::setlocale(LC_ALL, "");
// 遍历wstring,将宽字符转为UTF-8编码的字符,中文是三个字节长度
for (const auto& c: ws) {
char chars[3] = "";
std::wctomb(chars, c);
print("{}\t", chars);
}
println();
// 将字符串按照空格及其标点符号分割,L前缀用于标识宽字符
// 这里使用了现代C++中的range,通过管道运算符实现了字符串分割然后将分割结果转为wstring
auto Tokens = ws |
std::views::split(' ') |
std::ranges::to<vector<wstring>>();
// 这里使用了ranges的for_each函数,配合Lambda表达式进行wstring的输出
// 注意cout和print函数都不支持wstring,这里使用wcout进行输出
std::ranges::for_each(tokens, [](const auto& token) {
std::wcout << token << std::endl;
});
}
};
运行之后的结果如下图: