我改变了我的类,使用了std::string(基于我在这里得到的答案),但我有一个函数返回wchar_t*。如何将其转换为std::string?
我尝试过这样做:
std::string test = args.OptionArg();
但是它显示错误C2440: 'initializing':无法将'wchar_t *'转换为'std::basic_string<_Elem,_Traits,_Ax>'
std::wstring ws( args.OptionArg() );
std::string test( ws.begin(), ws.end() );
您可以使用以下函数将宽字符字符串转换为ASCII字符串:
#include <locale>
#include <sstream>
#include <string>
std::string ToNarrow( const wchar_t *s, char dfault = '?',
const std::locale& loc = std::locale() )
{
std::ostringstream stm;
while( *s != L'\0' ) {
stm << std::use_facet< std::ctype<wchar_t> >( loc ).narrow( *s++, dfault );
}
return stm.str();
}
请注意,这将使用 dfault
参数仅替换任何不存在等效ASCII字符的宽字符; 它不会从UTF-16转换为UTF-8。如果您想要转换为UTF-8,请使用诸如 ICU 的库。
令人失望的是,对于将宽字符串转换为UTF-8字符串的问题,这个老问题的任何答案都没有解决,这在非英语环境中非常重要。
以下是一个工作正常的示例代码,可以用作构建自定义转换器的提示。 它基于cppreference.com中的示例代码。
#include <iostream>
#include <clocale>
#include <string>
#include <cstdlib>
#include <array>
std::string convert(const std::wstring& wstr)
{
const int BUFF_SIZE = 7;
if (MB_CUR_MAX >= BUFF_SIZE) throw std::invalid_argument("BUFF_SIZE too small");
std::string result;
bool shifts = std::wctomb(nullptr, 0); // reset the conversion state
for (const wchar_t wc : wstr)
{
std::array<char, BUFF_SIZE> buffer;
const int ret = std::wctomb(buffer.data(), wc);
if (ret < 0) throw std::invalid_argument("inconvertible wide characters in the current locale");
buffer[ret] = '\0'; // make 'buffer' contain a C-style string
result = result + std::string(buffer.data());
}
return result;
}
int main()
{
auto loc = std::setlocale(LC_ALL, "en_US.utf8"); // UTF-8
if (loc == nullptr) throw std::logic_error("failed to set locale");
std::wstring wstr = L"aąß水-扫描-€\u00df\u6c34\U0001d10b";
std::cout << convert(wstr) << "\n";
}
这将按预期打印:
BUFF_SIZE
的最小安全值。它包括4作为单个字符最大UTF-8字节编码的可能性;2个用于可能的"shift sequence",1个用于尾部的'\0'
。MB_CUR_MAX
是一个运行时变量,因此在这里不能使用static_assert
std::wctomb
转换为其char
表示形式en_US.utf8
似乎足够通用(在大多数计算机上可用)。 在Linux中,可以通过控制台上的locale -a
命令查询可用的语言环境。最受欢迎的答案是:
std::wstring ws( args.OptionArg() );
std::string test( ws.begin(), ws.end() );
只有当广泛使用的字符表示ASCII字符时才能很好地工作-但这不是广泛使用的字符设计的目的。在这个解决方案中,转换后的字符串每个源宽字符包含一个字符,ws.size() == test.size()
。因此,它丢失了来自原始wstring的信息,并生成无法解释为正确的UTF-8序列的字符串。例如,在我的机器上,从“ĄŚĆII”的简单转换产生的字符串打印为“ZII”,即使其大小为5(应该是8)。
这是一个老问题,但如果你不是真正正在寻求转换而是使用来自微软的TCHAR工具来构建ASCII和Unicode,你可以回想一下std::string实际上是
typedef std::basic_string<char> string
因此,我们可以定义自己的typedef,例如:
#include <string>
namespace magic {
typedef std::basic_string<TCHAR> string;
}
然后您可以使用magic::string
与TCHAR
,LPCTSTR
等一起使用
wstring
并将所有内容保留在 Unicode 中。wchar_t wstr[500];
char string[500];
sprintf(string,"%ls",wstr);
仅供娱乐 :-):
const wchar_t* val = L"hello mfc";
std::string test((LPCTSTR)CString(val));
char c = static_cast<char>( wideChar )
,因此如果宽字符串字符不在ASCII范围内,它显然会丢失信息。 - zett42wchar_t
转换为std::string
的方法都会是有损转换,因为这是其定义所决定的。 - j bstd::string
的编码方式。例如,使用 UTF-8 编码时不会丢失信息。 - zett42