C ++将字符串(或char *)转换为wstring(或wchar_t *)

时间:2010-04-04 07:35:01

标签: c++ string wstring

string s = "おはよう";
wstring ws = FUNCTION(s, ws);

我如何将s的内容分配给ws?

搜索谷歌并使用了一些技巧,但他们无法分配确切的内容。内容是扭曲的。

18 个答案:

答案 0 :(得分:204)

假设你的例子中的输入字符串(おはよう)是UTF-8编码的(它的外观不是,但我们假设它是为了这个解释:-))表示您感兴趣的Unicode字符串,那么您的问题可以通过标准库(仅限C ++ 11和更新版本)完全解决。

TL; DR版本:

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

std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
std::string narrow = converter.to_bytes(wide_utf16_source_string);
std::wstring wide = converter.from_bytes(narrow_utf8_source_string);

更长的在线可编辑和可运行的示例:

(它们都显示了相同的例子。冗余只有很多......)

注意(旧)

正如评论中所指出并在https://stackoverflow.com/a/17106065/6345中解释的那样,有些情况下使用标准库在UTF-8和UTF-16之间进行转换可能会在不同平台上产生意外的差异。要获得更好的转化效果,请按照http://en.cppreference.com/w/cpp/locale/codecvt_utf8

中的说明考虑std::codecvt_utf8

注意(新)

由于在C ++ 17中不推荐使用codecvt标头,因此有人担心这个答案中提出的解决方案。但是,C ++标准委员会在http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0618r0.html中添加了一个重要声明

  

此库组件应随后退回附件D,直到合适的替代品标准化为止。

因此,在可预见的未来,此答案中的codecvt解决方案是安全且便携的。

答案 1 :(得分:44)

int StringToWString(std::wstring &ws, const std::string &s)
{
    std::wstring wsTmp(s.begin(), s.end());

    ws = wsTmp;

    return 0;
}

答案 2 :(得分:28)

您的问题未明确。严格来说,该示例是语法错误。但是,std::mbstowcs可能就是你要找的东西。

它是一个C库函数并在缓冲区上运行,但这是一个易于使用的成语,由TBohne(以前的Mooing Duck)提供:

std::wstring ws(s.size(), L' '); // Overestimate number of code points.
ws.resize(std::mbstowcs(&ws[0], s.c_str(), s.size())); // Shrink to fit.

答案 3 :(得分:17)

仅限Windows API,在C ++ 11实施之前,以防有人需要它:

#include <stdexcept>
#include <vector>
#include <windows.h>

using std::runtime_error;
using std::string;
using std::vector;
using std::wstring;

wstring utf8toUtf16(const string & str)
{
   if (str.empty())
      return wstring();

   size_t charsNeeded = ::MultiByteToWideChar(CP_UTF8, 0, 
      str.data(), (int)str.size(), NULL, 0);
   if (charsNeeded == 0)
      throw runtime_error("Failed converting UTF-8 string to UTF-16");

   vector<wchar_t> buffer(charsNeeded);
   int charsConverted = ::MultiByteToWideChar(CP_UTF8, 0, 
      str.data(), (int)str.size(), &buffer[0], buffer.size());
   if (charsConverted == 0)
      throw runtime_error("Failed converting UTF-8 string to UTF-16");

   return wstring(&buffer[0], charsConverted);
}

答案 4 :(得分:12)

如果您使用 Windows / Visual Studio 并需要将字符串转换为wstring,则可以使用:

#include <AtlBase.h>
#include <atlconv.h>
...
string s = "some string";
CA2W ca2w(s.c_str());
wstring w = ca2w;
printf("%s = %ls", s.c_str(), w.c_str());

将wstring转换为字符串的相同过程(有时您需要指定代码页):

#include <AtlBase.h>
#include <atlconv.h>
...
wstring w = L"some wstring";
CW2A cw2a(w.c_str());
string s = cw2a;
printf("%s = %ls", s.c_str(), w.c_str());

您可以指定代码页甚至UTF8(使用 JNI / Java 时非常好)。

CA2W ca2w(str, CP_UTF8);

如果您想了解有关 codepages 的更多信息,请参阅有关Joel on Software的有趣文章:The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets

这些CA2W(将Ansi转换为Wide = unicode)宏是ATL and MFC String Conversion Macros的一部分,包括样本。

有时您需要禁用安全警告#4995&#39;,我不知道其他解决方法(对我而言,当我在VS2012中为WindowsXp编译时会发生这种情况。)

#pragma warning(push)
#pragma warning(disable: 4995)
#include <AtlBase.h>
#include <atlconv.h>
#pragma warning(pop)

修改 好吧,根据this article,乔尔的文章似乎是:&#34;虽然很有趣,但实际的技术细节却非常清楚。文章:What Every Programmer Absolutely, Positively Needs To Know About Encoding And Character Sets To Work With Text

答案 5 :(得分:10)

char*wstring

char* str = "hello worlddd";
wstring wstr (str, str+strlen(str));

stringwstring

string str = "hello worlddd";
wstring wstr (str.begin(), str.end());

注意,只有在转换的字符串只包含ASCII字符时才能正常工作。

答案 6 :(得分:10)

这是将module ::I18n #... end string和混合字符串常量组合到wstring的方法。使用wstring类。

wstringstream

答案 7 :(得分:6)

使用Boost.Locale:

ws = boost::locale::conv::utf_to_utf<wchar_t>(s);

答案 8 :(得分:3)

这种变体是我现实生活中最喜欢的。它会将输入(如果有效) UTF-8转换为相应的wstring。如果输入已损坏,则wstring由单个字节构成。如果您无法确定输入数据的质量,这非常有用。

std::wstring convert(const std::string& input)
{
    try
    {
        std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
        return converter.from_bytes(input);
    }
    catch(std::range_error& e)
    {
        size_t length = input.length();
        std::wstring result;
        result.reserve(length);
        for(size_t i = 0; i < length; i++)
        {
            result.push_back(input[i] & 0xFF);
        }
        return result;
    }
}

答案 9 :(得分:1)

您可以使用 boost 路径或 std 路径;这要容易得多。 boost路径更容易跨平台应用

#include <boost/filesystem/path.hpp>

namespace fs = boost::filesystem;

//s to w
std::string s = "xxx";
auto w = fs::path(s).wstring();

//w to s
std::wstring w = L"xxx";
auto s = fs::path(w).string();

如果你喜欢使用标准:

#include <filesystem>
namespace fs = std::filesystem;

//The same

c++ 旧版本

#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;

//The same

其中的代码仍然实现了一个转换器,您不必解开细节。

答案 10 :(得分:1)

std::string -> wchar_t[],具有安全的mbstowcs_s功能:

auto ws = std::make_unique<wchar_t[]>(s.size() + 1);
mbstowcs_s(nullptr, ws.get(), s.size() + 1, s.c_str(), s.size());

这来自我的示例code

答案 11 :(得分:1)

字符串到字符串

std::wstring Str2Wstr(const std::string& str)
{
    int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
    std::wstring wstrTo(size_needed, 0);
    MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed);
    return wstrTo;
}

从字符串到字符串

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

答案 12 :(得分:1)

根据我自己的测试(在Windows 8,vs2010上),mbstowcs实际上可能会损坏原始字符串,它只适用于ANSI代码页。如果MultiByteToWideChar / WideCharToMultiByte也会导致字符串损坏 - 但它们倾向于用'?'替换他们不知道的字符。问号,但mbstowcs往往会遇到未知的字符并在那一点切断字符串。 (我在芬兰的窗户上测试了越南人物)。

所以更喜欢Multi * -windows api函数而不是模拟ansi C函数。

另外我注意到将字符串从一个代码页编码到另一个代码页的最短路径不是使用MultiByteToWideChar / WideCharToMultiByte api函数调用,而是使用它们的模拟ATL宏:W2A / A2W。

所以上面提到的模拟功能听起来像是:

wstring utf8toUtf16(const string & str)
{
   USES_CONVERSION;
   _acp = CP_UTF8;
   return A2W( str.c_str() );
}

_acp在USES_CONVERSION宏中声明。

或者在执行旧数据转换为新数据时经常会错过的功能:

string ansi2utf8( const string& s )
{
   USES_CONVERSION;
   _acp = CP_ACP;
   wchar_t* pw = A2W( s.c_str() );

   _acp = CP_UTF8;
   return W2A( pw );
}

但是请注意那些宏使用大量堆栈 - 不要使用for循环或递归循环来使用相同的函数 - 在使用W2A或A2W宏之后 - 最好尽快返回,因此堆栈将从临时转换中解放出来。

答案 13 :(得分:1)

方法s2ws效果很好。希望有所帮助。

std::wstring s2ws(const std::string& s) {
    std::string curLocale = setlocale(LC_ALL, ""); 
    const char* _Source = s.c_str();
    size_t _Dsize = mbstowcs(NULL, _Source, 0) + 1;
    wchar_t *_Dest = new wchar_t[_Dsize];
    wmemset(_Dest, 0, _Dsize);
    mbstowcs(_Dest,_Source,_Dsize);
    std::wstring result = _Dest;
    delete []_Dest;
    setlocale(LC_ALL, curLocale.c_str());
    return result;
}

答案 14 :(得分:0)

如果您有QT,并且懒于实现功能和东西,则可以使用

std :: string str; QString(str).toStdWString()

答案 15 :(得分:0)

这是我的超级基本解决方案,可能不适用于每个人。但是对于很多人来说都是有效的。

它需要使用指南支持库。 这是由许多C ++委员会作者设计的漂亮的官方C ++库:

    std::string to_string(std::wstring const & wStr)
    {
        std::string temp = {};

        for (wchar_t const & wCh : wStr)
        {
            // If the string can't be converted gsl::narrow will throw
            temp.push_back(gsl::narrow<char>(wCh));
        }

        return temp;
    }

我所有的功能是尽可能地允许转换。否则引发异常。

通过gsl :: narrow(https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#es49-if-you-must-use-a-cast-use-a-named-cast)的使用

答案 16 :(得分:-1)

string s = "おはよう";是一个错误。

你应该直接使用wstring:

wstring ws = L"おはよう";

答案 17 :(得分:-2)

使用此代码将字符串转换为wstring

std::wstring string2wString(const std::string& s){
    int len;
    int slength = (int)s.length() + 1;
    len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0); 
    wchar_t* buf = new wchar_t[len];
    MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, buf, len);
    std::wstring r(buf);
    delete[] buf;
    return r;
}

int main(){
    std::wstring str="your string";
    std::wstring wStr=string2wString(str);
    return 0;
}