Compare std::wstring and std::string
Compare std::wstring and std::string
如何比较wstring
,例如L"Hello"
和string
?如果我需要相同的类型,我如何将它们转换为相同的类型?
既然你问了,这是我的标准转换函数从字符串到宽字符串,使用c++ std::string
和std::wstring
类实现。
首先,确保用set_locale
:
#include <clocale>
int main()
{
std::setlocale(LC_CTYPE, ""); // before any string operations
}
现在是函数。首先,从窄字符串中获取宽字符串:
#include <string>
#include <vector>
#include <cassert>
#include <cstdlib>
#include <cwchar>
#include <cerrno>
// Dummy overload
std::wstring get_wstring(const std::wstring & s)
{
return s;
}
// Real worker
std::wstring get_wstring(const std::string & s)
{
const char * cs = s.c_str();
const size_t wn = std::mbsrtowcs(NULL, &cs, 0, NULL);
if (wn == size_t(-1))
{
std::cout << "Error in mbsrtowcs(): " << errno << std::endl;
return L"";
}
std::vector<wchar_t> buf(wn + 1);
const size_t wn_again = std::mbsrtowcs(buf.data(), &cs, wn + 1, NULL);
if (wn_again == size_t(-1))
{
std::cout << "Error in mbsrtowcs(): " << errno << std::endl;
return L"";
}
assert(cs == NULL); // successful conversion
return std::wstring(buf.data(), wn);
}
往回看,从宽弦变成窄弦。我将窄字符串称为"locale string",因为它是依赖于平台的编码,取决于当前的locale:
// Dummy
std::string get_locale_string(const std::string & s)
{
return s;
}
// Real worker
std::string get_locale_string(const std::wstring & s)
{
const wchar_t * cs = s.c_str();
const size_t wn = std::wcsrtombs(NULL, &cs, 0, NULL);
if (wn == size_t(-1))
{
std::cout << "Error in wcsrtombs(): " << errno << std::endl;
return "";
}
std::vector<char> buf(wn + 1);
const size_t wn_again = std::wcsrtombs(buf.data(), &cs, wn + 1, NULL);
if (wn_again == size_t(-1))
{
std::cout << "Error in wcsrtombs(): " << errno << std::endl;
return "";
}
assert(cs == NULL); // successful conversion
return std::string(buf.data(), wn);
}
一些注意事项:
- 如果你没有
std::vector::data()
,你可以用&buf[0]
代替。 - 我发现
r
风格的转换函数mbsrtowcs
和wcsrtombs
在Windows上不能正常工作。在那里,你可以使用mbstowcs
和wcstombs
代替:mbstowcs(buf.data(), cs, wn + 1);
,wcstombs(buf.data(), cs, wn + 1);
回答你的问题,如果你想比较两个字符串,你可以将它们都转换为宽字符串,然后比较它们。如果你正在从磁盘读取一个已知编码的文件,你应该使用iconv()
将文件从已知编码转换为WCHAR,然后与宽字符串进行比较。
您应该使用mbstowcs
将char
字符串转换为wchar_t
字符串,然后比较结果字符串。注意,mbstowcs
适用于char *
/wchar *
,所以您可能需要做这样的事情:
std::wstring StringToWstring(const std::string & source)
{
std::wstring target(source.size()+1, L' ');
std::size_t newLength=std::mbstowcs(&target[0], source.c_str(), target.size());
target.resize(newLength);
return target;
}
我不完全确定&target[0]
的使用是否完全符合标准,如果有人对此有好的答案,请在评论中告诉我。此外,还有一个隐含的假设,即转换后的字符串不会比原始字符串的wchar_t
s的数量更长(以CC_24 s为单位)——这是一个逻辑假设,我仍然不确定它是否被标准所涵盖。
另一方面,似乎没有办法要求mbstowcs
所需缓冲区的大小,所以你要么这样做,要么从Unicode库(无论是Windows api还是像iconv这样的库)中使用(更好地完成和更好地定义)代码。
但是,请记住,在不使用特殊函数的情况下比较Unicode字符串是很危险的,两个等效字符串在按位比较时可能求值不同。
长话短说:这应该工作,我认为这是你能做的最大的标准库,但它是很多实现依赖于Unicode是如何处理的,我不会相信它很多。一般来说,最好在应用程序中使用一种编码,除非绝对必要,否则避免这种转换,并且,如果您正在使用确定的编码,请使用与实现依赖程度较低的api。
在这样做之前要三思——您可能一开始就不想比较它们。如果你确定你这样做,你正在使用Windows,然后用MultiByteToWideChar转换string
到wstring
,然后与CompareStringEx比较。
如果您不使用Windows,那么类似的函数是mbstowcs
和wcscmp
。标准的宽字符c++函数通常不能在Windows下移植;例如,mbstowcs
已弃用。
使用Unicode的跨平台方法是使用ICU库。
注意使用Unicode字符串比较的特殊函数,不要手动操作。两个Unicode字符串可以有不同的字符,但仍然是相同的。
wstring ConvertToUnicode(const string & str)
{
UINT codePage = CP_ACP;
DWORD flags = 0;
int resultSize = MultiByteToWideChar
( codePage // CodePage
, flags // dwFlags
, str.c_str() // lpMultiByteStr
, str.length() // cbMultiByte
, NULL // lpWideCharStr
, 0 // cchWideChar
);
vector<wchar_t> result(resultSize + 1);
MultiByteToWideChar
( codePage // CodePage
, flags // dwFlags
, str.c_str() // lpMultiByteStr
, str.length() // cbMultiByte
, &result[0] // lpWideCharStr
, resultSize // cchWideChar
);
return &result[0];
}
- cppcheck在const std::string[]上引发警告
- 将std::string传递给WriteConsole API
- 为std::string的某个索引赋值
- 使用 std::string () const 函数启动线程或未来
- 当我们进行一些操作时,应该使用什么'std::string'或'std::stringstream'?
- 如何更改大小(std::string)
- std::string 的对象真的可以移动吗?
- SegFault 同时使用 std::string::operator+= 和函数作为参数
- 无法从 std::string 中提取C++ Unicode 符号
- std::string 构造函数如何处理固定大小的 char[]?
- 真的没有来自 std::string_view 的 std::string 的显式构造函数吗?
- 将C++ std::string 转换为 UTF-16-LE 编码的字符串
- 重载 + 自己的类和 std::string 的运算符
- 如何使用 std::string 作为 QHash 的键?
- 将日语 wstring 转换为 std::string
- 可以从std::string继承以提供类型一致性吗
- 构造函数采用std::string_view与std::string并移动
- 在共享缓冲区内存中创建 ::std::string 对象
- std::string.size() 未知行为
- Valgrind 在 std::string::swap 中报告 SIGILL