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

Sam*_*mir 157 c++ string wstring

string s = "????";
wstring ws = FUNCTION(s, ws);
Run Code Online (Sandbox Code Playgroud)

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

搜索谷歌并使用了一些技术,但他们无法分配确切的内容.内容失真.

Joh*_*ell 218

假设您的示例中的输入字符串(おはよう)是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);
Run Code Online (Sandbox Code Playgroud)

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

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

注意(旧):

正如在评论中指出并在/sf/answers/1197424581/中解释的那样,有些情况下使用标准库在UTF-8和UTF-16之间进行转换可能会在不同平台上产生意外的差异.为了更好的转换,可以考虑std::codecvt_utf8作为描述http://en.cppreference.com/w/cpp/locale/codecvt_utf8

注意(新):

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

该库组件应随后退回附件D,直到合适的替代品标准化.

所以在可预见的未来,codecvt这个答案的解决方案是安全和便携的.

  • 请注意,自从C++ 17以来,不推荐使用`<codecvt>`. (11认同)
  • 请注意,这只是C++ 11! (9认同)
  • 检查用什么编码保存VS文件 (2认同)
  • @tambre - 感谢您指出这一点,我添加了 **Note (new)** 段落来解决这个问题。 (2认同)
  • 如果我是这个世界上唯一的、全能的统治者,我会下令,UTF16 是非法的,只有 UTF8 和 UTF32 是合法的和可用的,而且不会有受到严厉惩罚的危险。;) 我认真的说 - 如果 UTF16 仍然是多代码点,那么它有什么好处?!恕我直言,所有这些转换麻烦的根本原因是 UTF16 有缺陷。 (2认同)

Pie*_*o M 49

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

    ws = wsTmp;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • 仅当所有字符都是单字节时才有效,即ASCII或[ISO-8859-1](http://en.wikipedia.org/wiki/ISO-8859-1).任何多字节都会失败,包括UTF-8.问题显然包含多字节字符. (88认同)
  • 这个答案显然是不够的,除了将宽窄的字符复制成宽字符外什么都不做.请参阅其他答案,特别是Johann Gerell的答案,了解如何从多字节或utf8编码的字符串正确地转换为utf16 wstring. (25认同)
  • 这个答案是危险的,可能会破坏非ascii系统.即阿拉伯语文件名将被这个黑客攻击. (8认同)
  • 如果您忽略问题主体的细微差别并关注问题标题,这个答案很有用,这就是我从谷歌带来的问题.因此,问题的标题是*非常*误导性的,应该进行修改以反映所提出的真实问题 (5认同)
  • 这仅适用于7位ASCII字符.对于latin1,仅当char配置为unsigned时才有效.如果char类型已签名(大多数情况下都是这种情况),则字符> 127将给出错误的结果. (2认同)
  • 如果您希望这种类型的转换可靠地工作,请执行std :: wstring c(const std :: string&i){size_t n = i.length(); std :: wstring o; o。 reserve(n); for(size_t p = 0; p &lt;n; ++ p)o.push_back(i [p]&255); return o;}`-诀窍是`&255`。 (2认同)

Pot*_*ter 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.
Run Code Online (Sandbox Code Playgroud)

  • `std::string ws(s.size()); ws.resize(mbstowcs(&amp;ws[0], s.c_str(), s.size());` RAII FTW (2认同)
  • @WaffleSouffle这已经过时了.自2011年以来一直需要连续实现,并且实现在此之前很久就会退出这些技巧. (2认同)

Ale*_*Che 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);
}
Run Code Online (Sandbox Code Playgroud)

  • @c00000fd,据我所知,仅自 C++11 标准以来, std::basic_string 内部缓冲区才需要连续。我的代码是 C++11 之前的代码,如帖子顶部所述。因此, &amp;strW[0] 代码不符合标准,并且可能在运行时正常崩溃。 (3认同)

lmi*_*lmh 11

如果您使用的是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());
Run Code Online (Sandbox Code Playgroud)

将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());
Run Code Online (Sandbox Code Playgroud)

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

// 
// 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);
}
Run Code Online (Sandbox Code Playgroud)

如果你想了解更多关于代码页的信息,可以在Joel on Software上找到一篇有趣的文章:绝对最低的每个软件开发人员,绝对必须知道关于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)
Run Code Online (Sandbox Code Playgroud)

编辑: 嗯,根据这篇文章,乔尔的文章似乎是:"在娱乐的时候,实际的技术细节非常清晰".文章:每个程序员绝对需要了解编码和字符集以处理文本.


Mar*_*ata 11

这里有一个方法相结合string,wstring并混合字符串常量wstring.使用该wstringstream课程.

#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();
Run Code Online (Sandbox Code Playgroud)

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

Gho*_*jad 9

从:char*wstring:

char* str = "hello worlddd";
wstring wstr (str, str+strlen(str));
Run Code Online (Sandbox Code Playgroud)

从:stringwstring:

string str = "hello worlddd";
wstring wstr (str.begin(), str.end());
Run Code Online (Sandbox Code Playgroud)

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

  • 因为这仅在编码为Windows-1252时才有效,而Windows-1252甚至无法保存问题中的字母. (7认同)
  • 当您知道要处理ASCII时,这是最不容易出错的方式。将应用程序移植到较新的api时,这是一个突出的用例。 (3认同)

vla*_*don 7

使用Boost.Locale:

ws = boost::locale::conv::utf_to_utf<wchar_t>(s);
Run Code Online (Sandbox Code Playgroud)


Ale*_*ker 7

您可以使用 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();
Run Code Online (Sandbox Code Playgroud)

如果你喜欢使用 std:

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

//The same
Run Code Online (Sandbox Code Playgroud)

C++旧版本

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

//The same
Run Code Online (Sandbox Code Playgroud)

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


Mat*_*nge 5

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

  • 我刚刚根据您的回答推出了这个问题 /sf/ask/3476833391/#49669048你能看一下吗 (2认同)

Mic*_*tos 5

对我来说,最简单且开销不大的选项是:

包括:

#include <atlbase.h>
#include <atlconv.h>
Run Code Online (Sandbox Code Playgroud)

转变:

char* whatever = "test1234";
std::wstring lwhatever = std::wstring(CA2W(std::string(whatever).c_str()));
Run Code Online (Sandbox Code Playgroud)

如果需要的话:

lwhatever.c_str();
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

243826 次

最近记录:

6 年,1 月 前