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


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

在google中搜索并使用了一些技术,但它们无法分配确切的内容。内容失真。

评论

我认为字符串不接受> 8位字符。它已经用UTF-8编码了吗?

您的系统编码是什么,它将使“おはよう”成为系统编码的字符串?

我相信MSVC会接受它,并对其进行一些多字节编码,也许是UTF-8。

@Potatoswatter:默认情况下,MSVC不使用UTF-8。如果输入这些字符,它将询问将文件转换为哪种编码,并且默认为代码页1252。

@Samir:更重要的是文件的编码是什么?您可以将该字符串移动到文件的开头并显示该部分的十六进制转储吗?我们可能可以从中识别出它。

#1 楼

假设示例(おはよう)中的输入字符串是UTF-8编码的(从外观上看不是,但是为了解释起见,我们假设它是:-))是Unicode字符串的表示形式如果您感兴趣,那么仅使用标准库(C ++ 11和更高版本)就可以完全解决您的问题。


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


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

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


http://ideone.com/KA1oty
http://ide.geeksforgeeks.org/5pRLSh
http://rextester.com/DIJZK52174

注意(旧) :

如注释中所指出并在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解决方案是安全且可移植的。

评论


检查保存VS文件时使用的编码方式

–约翰·格瑞尔(Johann Gerell)
13年8月8日在10:39

请注意,这仅适用于C ++ 11!

–bk138
2014年1月15日13:58

在minGW(gcc / g ++ 4.8.1和-std = c ++ 11)中,codecvt标头不存在。还有其他选择吗?

–布赖恩·杰克(Brian Jack)
2014年12月11日,19:34

请您为初学者提供std :: codecvt_utf8的示例

– Noitidart
17-2-23在0:22

请注意,自C ++ 17开始不推荐使用

– tambre
17年4月9日在11:01

#2 楼

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

    ws = wsTmp;

    return 0;
}


评论


仅当所有字符均为单个字节(即ASCII或ISO-8859-1)时,此方法才有效。任何多字节的内容都会惨遭失败,包括UTF-8。该问题显然包含多字节字符。

– Mark Ransom
2013年9月3日在16:22

这个答案显然是不够的,除了将窄字符照原样复制为宽字符之外,什么也没有做。有关如何正确地将多字节或utf8编码的字符串转换为utf16 wstring的信息,请参见其他答案,尤其是Johann Gerell的答案。

– DLRdave
13-10-13在11:29

这个答案很危险,可能会在非ASCII系统上中断。即阿拉伯文文件名将被此黑客破坏。

–斯蒂芬
2014年4月18日19:50

如果您忽略了问题正文的细微差别,而是专注于问题标题,那么这个答案将非常有用。实际上,该问题的标题极具误导性,应进行更改以反映所提出的真实问题

–安妮·奎因(Anne Quinn)
2015年12月17日在7:37

这仅适用于7位ASCII字符。对于latin1,仅当char配置为unsigned时,它才有效。如果char类型是带符号的(多数情况下是这种情况),则字符> 127将给出错误的结果。

–huyc
16年5月16日在18:32

#3 楼

您的问题未指定。严格来说,该示例是语法错误。但是,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.


评论


字符串s =“おはよう”; wchar_t * buf = new wchar_t [s.size()]; size_t num_chars = mbstowcs(buf,s.c_str(),s.size()); wstring ws(buf,num_chars); // ws =扭曲

–萨米尔
10-4-4在8:23

@Samir:您必须确保运行时编码与编译时编码相同。您可能需要setlocale或调整编译器标志。我不知道,因为我不使用Windows,但这就是为什么它不常见的原因。如果可能,请考虑其他答案。

–马铃薯
10年4月4日在9:30

std :: string ws(s.size()); ws.resize(mbstowcs(&ws [0],s.c_str(),s.size()); RAII FTW

–鸭鸭
2013年9月3日在17:01

@WaffleSouffle那已经过时了。自2011年以来,就需要连续的实现,而在此之前,实现就已经摆脱了这种麻烦。

–马铃薯
2014-09-22 23:53

并且像mingw这样的某些环境仍然没有codecvt标头,因此早期的一些“更好”的解决方案无法正常工作,这意味着即使到2014年12月,此问题在mingw中仍然没有好的解决方案

–布赖恩·杰克(Brian Jack)
2014年12月11日,19:54

#4 楼

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


评论


您可以对其进行优化。无需使用向量对字符串进行双重复制。只需通过执行wstring strW(charsNeeded + 1)保留字符串中的字符即可;然后将其用作转换缓冲区:&strW [0]。最后,通过执行strW [charsNeeded] = 0来确保转换后存在最后一个null。

–c00000fd
17-2-6在3:35



据我所知,@ c00000fd仅自C ++ 11标准以来才要求std :: basic_string内部缓冲区是连续的。我的代码是C ++ 11之前的版本,如文章顶部所述。因此,&strW [0]代码将不符合标准,并且可能在运行时合法崩溃。

– Alex Che
17年2月6日在7:03

#5 楼

如果您使用的是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时非常好)。此答案中显示了将std :: wstring转换为utf8 std :: string的标准方法。

// 
// using ATL
CA2W ca2w(str, CP_UTF8);

// 
// or the standard way taken from the answer above
#include <codecvt>
#include <string>

// convert UTF-8 string to wstring
std::wstring utf8_to_wstring (const std::string& str) {
    std::wstring_convert<std::codecvt_utf8<wchar_t>> myconv;
    return myconv.from_bytes(str);
}

// convert wstring to UTF-8 string
std::string wstring_to_utf8 (const std::wstring& str) {
    std::wstring_convert<std::codecvt_utf8<wchar_t>> myconv;
    return myconv.to_bytes(str);
}


如果您想了解有关代码页的更多信息,关于Joel关于软件的有趣文章:绝对绝对是每个软件开发人员绝对,肯定必须了解Unicode和字符集。

这些CA2W(将Ansi转换为Wide = unicode)宏是ATL和MFC字符串转换宏(包括示例)的一部分。

有时您需要禁用安全警告#4995',我不知道其他解决方法(对我来说,是在VS2012中为WindowsXp编译时发生的)。

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


编辑:
根据这篇文章,Joel的文章似乎是:“在娱乐的同时,对实际的技术细节也相当轻巧”。文章:每个程序员绝对肯定要了解与文本配合使用的编码和字符集。

评论


抱歉,我不是英语母语人士。请根据需要编辑。

– lmiguelmh
2014年11月10日14:56

下注者怎么了?答案有什么问题?

– lmiguelmh
15年6月16日在21:47

它促进非便携式代码的事实。

– Pavel Minaev
15年8月24日在23:11

是的,这就是为什么我说这仅在Windows / Visual Studio中有效。但是至少这个解决方案是正确的,而不是正确的:char * str =“ hello worlddd”; wstring wstr(str,str + strlen(str));

– lmiguelmh
2015年8月25日在23:07



附加说明:CA2W在ATL的命名空间下。 (ATL :: CA2W)

–Val
16 Mar 22 '16 at 8:55

#6 楼

这是将stringwstring和混合的字符串常量组合到wstring的方法。使用wstringstream类。

不适用于多字节字符编码。这只是丢弃类型安全性并将std :: string的7位字符扩展为std:wstring的每个字符的低7位的愚蠢方法。仅当您具有7位ASCII字符串并且需要调用需要宽字符串的API时,此功能才有用。

#include <sstream>

std::string narrow = "narrow";
std::wstring wide = L"wide";

std::wstringstream cls;
cls << " abc " << narrow.c_str() << L" def " << wide.c_str();
std::wstring total= cls.str();


评论


答案似乎很有趣。您能否解释一下:这对多字节编码有效吗?为什么/如何做?

– wh1t3cat1k
2015年11月14日在8:23



编码方案与存储类别正交。 string存储1个字节字符,wstring存储2个字节字符。像utf8这样的东西会将多字节字符存储为一系列1字节值,即字符串。字符串类对编码没有帮助。我不是用c ++编码类的专家。

–马克·拉卡塔(Mark Lakata)
2015年11月14日在16:40

考虑到它多么简短,有什么理由不是最佳答案?有没有涵盖的情况?

–龙
18年5月4日在9:56

@MarkLakata,我阅读了您对第一条评论的回答,但仍不确定。它适用于多字节字符吗?换句话说,它不容易与该答案有同样的陷阱吗?

– Marc.2377
19 Sep 10'在6:42

@ Marc.2377这不适用于多字节字符编码。这只是丢弃类型安全性并将std :: string的7位字符扩展为std:wstring的每个字符的低7位的愚蠢方法。仅当您具有7位ASCII字符串并且需要调用需要宽字符串的API时,此功能才有用。如果您需要更高级的功能,请访问stackoverflow.com/a/8969776/3258851。

–马克·拉卡塔(Mark Lakata)
19-09-10在22:42

#7 楼

char*wstring

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


stringwstring

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


请注意,只有当要转换的字符串仅包含ASCII字符。

评论


因为这仅在编码为Windows-1252的情况下有效,该编码甚至不能容纳问题中的字母。

–鸭鸭
2013年9月4日在16:54

当您知道要处理ASCII时,这是最不容易出错的方式。将应用程序移植到较新的api时,这是一个突出的用例。

– Sid Sarasvati
2014-2-25在19:45

不是这样的如果使用的是Visual Studio,则应使用atlconv.h。检查其他答案。

– lmiguelmh
2014年11月5日22:50

#8 楼

使用Boost.Locale:

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


#9 楼

它的这种变体是我在现实生活中最喜欢的。它将输入(如果它是有效的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;
    }
}


评论


我刚刚根据您的答案启动了这个问题stackoverflow.com/questions/49669048 / ...请您看看

– MistyD
18-4-5在9:51



#10 楼

如果您有QT,并且懒于实现功能和东西,则可以使用
std::string str;
QString(str).toStdWString()


评论


几乎可以,但是您应该从QString开始,因为QString构造函数由于某种原因不能接受字符串。

–bobsbeenjamin
5月20日10:56

您可以使用doc.qt.io/qt-5/qstring.html#fromStdString

– Kadir Erdem Demir
5月20日11:00

很好另外,您可以使用.c_str()让QString在构造函数中接受您的字符串。

– miep
7月1日9:46

#11 楼

方法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;
}


评论


所有这些答案如何以不安全的方式分配动态内存,然后将数据从缓冲区复制到字符串?为什么没有人摆脱不安全的中间人?

–鸭鸭
2013年9月4日16:56

hahakubile,您能为ws2s提供类似的帮助吗?

–克里斯蒂安
16年9月9日在15:32

#12 楼

根据我自己的测试(在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 );
}


但是请注意,这些宏占用大量堆栈-请勿用于同一功能的循环或递归循环-使用W2A或A2W宏后-最好返回ASAP,因此可以从中释放堆栈临时转换。

#13 楼

字符串到wstring

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


字符串到wstring

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


评论


该Str2Wstr的终止为0。不再可以通过“ +”连接生成的wstring(就像在wstring s3 = s1 + s2中一样)。我将尽快解决这个问题。首先必须对内存泄漏进行一些测试。

–thewhiteambit
1月6日18:51



#14 楼

带安全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());

这是我的示例代码

#15 楼

这是我的超级基本解决方案,可能不适用于所有人。但是会为很多人工作。
它需要使用指南支持库。
这是一个由许多C ++委员会作者设计的漂亮的官方C ++库:

https://github.com/isocpp/CppCoreGuidelines
https://github.com/Microsoft/GSL

    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-强制使用命名转换)

#16 楼

使用此代码将您的字符串转换为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;
}


评论


请注意,该问题没有提及Windows,并且此答案仅适用于Windows。

–约翰·格瑞尔(Johann Gerell)
15年8月27日在14:11

CP_ACP无疑是错误的论点。突然之间,正在执行的线程的环境状态会影响代码的行为。不建议。在转换中指定固定的字符编码。 (并考虑处理错误。)

– IInspectable
16年1月12日,0:56

#17 楼

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

应直接使用wstring:

wstring ws = L"おはよう";


评论


那也不行。您必须将那些非BMP字符转换为C转义序列。

–戴夫·范·登·艾恩德
10-4-4在7:49

@Dave:如果您的编译器支持源文件中的Unicode,并且过去十年中的所有代码都支持(Visual Studio,gcc等),它确实可以工作

–托马斯·博尼尼(Thomas Bonini)
10-4-4在7:52

嗨,无论使用默认的系统编码(例如,我可能使用阿拉伯语作为默认的系统编码),L“おはよう”的源代码文件的编码应如何工作?应该是UTF-16,还是我可以拥有不带BOM的UTF-8用于.cpp文件编码?

–非洲A. Arief
10年8月12日在4:26



@afriza:没关系,只要您的编译支持

–托马斯·博尼尼(Thomas Bonini)
2010年8月12日14:00

这不是错误;定义了“窄”字符串中的扩展字符以映射到多字节序列。只要操作系统支持,编译器就应该支持它,这是您要求的最低要求。

–马铃薯
13-10-13在0:35