C++
August 29, 2024

C++字符串中文字符处理初探

版权声明:本文为博主原创文章,转载请注明原文出处!

作者:阿振

写作时间:2024-08-29 09:32:15


C++字符串中文字符处理初探

好久没有写博客了,工作忙得都快忘记自己之前还有写博客的习惯。今天我们简单聊一下C++中如何处理中文字符。学过C++的都知道标准库中的 std::string更像是一个存储着 char的容器,而不是普遍意义上的字符串。而我们的中文字符又无法使用单个 char进行存储。

常见用于中文的的字符编码有 GBKUTF-8UTF-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进行。当然,如果你需要进行复杂的字符串处理,可以通过第三方库例如,ICUQtPoco等,这些第三方库提供了很多强大的功能。

下面程序演示了如何进行两者的转化,最后将转换后的 std::wstring使用空格进行分割输出(程序在macOS上运行通过,在Windows下可能还需要额外工作)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
module;
// Created by Victor Tan on 8/28/24.
// 中文字符串使用

#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;
});
}
};

运行之后的结果如下图:
C++中文String