此方一泉 10 X 10
此方一泉:~/blog$ source "C++中文字符处理(宽字符转换).sh"

此方一泉:~/blog$ printenv
CREATED_DATE = 2019-03-06
UPDATED_DATE = 2020-02-20
TAGS = c++11 : c++
CATEGORIES = programming

此方一泉:~/blog$ grep -lr $TAGS post
2019-01-10 c++11 thread_local 用法
2019-03-06 C++中文字符处理(宽字符转换)
C++中文字符处理(宽字符转换)

C++中文字符处理(宽字符转换)

std::string vs std::wstring

一般情况下,我们使用c++处理字符串都使用的是string来处理。但在处理中文时,string的一些方法不能达到我们想要的效果,比如:size()函数返回的是中文字符串所占的字节数。

1
2
string s = "今天天气123";
cout << s.size() << endl;

1
15

而我们想要得到我们日常理解的字符数:7
这里我们使用宽字符就可以达到目的:

1
2
wstring s = L"今天天气123";
cout << s.size() << endl;

1
7

下面就介绍一下如何使string与w_string进行互转:

c++11(gcc5以上版本)

在c++11中比较简单,直接使用std::wstring_convert() 函数就可以进行互转。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

#include <string>
#include <locale>
#include <codecvt>

std::wstring s2ws(const std::string& str) {
using convert_typeX = std::codecvt_utf8<wchar_t>;
std::wstring_convert<convert_typeX, wchar_t> converterX;
return converterX.from_bytes(str);
}

std::string ws2s(const std::wstring& wstr) {
using convert_typeX = std::codecvt_utf8<wchar_t>;
std::wstring_convert<convert_typeX, wchar_t> converterX;
return converterX.to_bytes(wstr);
}

但需要注意的是经常使用的gcc 4.8版本明确不支持这个函数,需要gcc 5才可以使用。所以本人没有具体验证过 (捂脸)

gcc 4.8

对于gcc4.8就只能使用clib的函数来转换了。
主要用到的是:wcstombs()mbstowcs()

wcstombs

函数说明:

std::wcstombs
#include
std::size_t wcstombs( char dst, const wchar_t src, std::size_t len);
从wchar_t src转换成char dstlen为dst buffer的最大值。
返回值为转换的字节数(不包括\0),出错返回 -1.

举例
1
2
3
4
5
6
7
8
9
10
11
12
#include <clocale>
#include <cstdlib>

setlocale(LC_ALL, "");
wstring ws = L"今天天气";
cout << ws.size() << endl;
int len = wcslen(ws.c_str());
cout << "wcslen:" << len << endl;
char str_buf[100];
int n = wcstombs(str_buf, ws.c_str(), 100);
string out = string(str_buf, n);
cout << "w > s(" << out << "):" << out.size() << endl;
1
2
3
4
wcslen:4
w > s(今天天气):12

mbstowcs

函数说明:

std::mbstowcs
#include
std::size_t mbstowcs( wchar_t dst, const char src, std::size_t len);
从char src转换到wchar_t dstlen为dst buffer的最大值。
返回值为宽字节个数(不包括\0),出错返回 -1

举例
1
2
3
4
5
6
7
8
9
10
#include <clocale>
#include <cstdlib>

setlocale(LC_ALL, "");
string s = "今天天气123";
cout << s.size() << endl;
wchar_t wstr_buf[100];
int m = mbstowcs(wstr_buf, s.c_str(), 100);
wstring wout = wstring(wstr_buf, m);
cout << "s > w:" << wout.size() << endl;
1
2
15
s > w:7

find举例

1
2
3
4
5
6
7
8
9
10
11
12
13
//接上块代码
wstring ws_q = L"天气";
size_t p = wout.find(ws_q);
if (p != std::string::npos) {
cout<< "ws find:" << p << endl;
} else {
cout<< "not find:" << p << endl;
}
string q = "天气";
size_t q_pos = s.find(q);
if (q_pos != std::string::npos) {
cout << "s find:" << q_pos << endl;
}
1
2
ws find:2
s find:6

wstring会直接返回中文字符数。string的find会返回实际字节数

引用

How to convert wstring into string?
std::codecvt_utf8
std::wstring_convert
Is codecvt not a std header?
GCC 5 Release Series: Changes, New Features, and Fixes
std::mbstowcs
std::wcstombs