如何将wstring
(例如L"Hello"
)与string
进行比较?如果我需要具有相同的类型,我如何将它们转换为相同的类型?
答案 0 :(得分:6)
因为您问过,这是我的标准转换函数,从字符串到宽字符串,使用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”,因为它取决于当前的语言环境,采用依赖于平台的编码:
// 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,然后与宽字符串进行比较。
请注意,复杂的Unicode文本可能有多个不同的表示作为您可能需要考虑的代码点序列。如果可能,您需要使用更高级别的Unicode处理库(例如ICU)并将字符串规范化为一些常见的可比较形式。
答案 1 :(得分:3)
您应该使用char
将wchar_t
字符串转换为mbstowcs
字符串,然后比较生成的字符串。请注意,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
个数更长(数量为char
s) - 这是一个逻辑假设,我仍然不是确定它符合标准。
另一方面,似乎无法向mbstowcs
询问所需缓冲区的大小,因此要么采用这种方式,要么使用(更好地完成和更好定义的)Unicode库中的代码(无论是Windows API还是像iconv这样的库)。
尽管如此,请记住,在不使用特殊功能的情况下比较Unicode字符串是很滑的,当按位比较时,两个等效的字符串可能会有不同的评估。
长话短说:这应该可以工作,我认为这是标准库所能达到的最大值,但它在很大程度上取决于Unicode的处理方式,我不会相信它。一般来说,最好在应用程序中坚持使用编码并避免这种转换,除非绝对必要,并且,如果您正在使用明确的编码,请使用与实现相关性较低的API。
答案 2 :(得分:2)
在执行此操作之前请三思而后行 - 您可能不想首先比较它们。如果您确定要使用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];
}