C++将数据从 std::string 复制到 std::wstring
C++ copy data from std::string to std::wstring
假设我有一个std::string
,但数据是用UTF-16编码的。
如何将该数据复制到std::wstring
中,根本不修改数据?
此外,我不能只使用 std::wstring
,因为我正在在线检索文本文件并检查 Content-Type
标头字段以确定编码。但是使用std::string
来接收数据。
std::wstring PackUTF16(const std::string & input)
{
if (input.size() % 2 != 0)
throw std::invalid_argument("input length must be even");
std::wstring result(input.size() / 2, 0);
for (int i = 0; i < result.size(); ++i)
{
result[i] = (input[2*i+1] & 0xff) << 8 | (input[2*i] & 0xff); // for little endian
//result[i] = (input[2*i] & 0xff) << 8 | (input[2*i+1] & 0xff); // for big endian
}
return result;
}
试试这个:
static inline std::wstring charToWide(const std::string & s_in)
{
const char * cs = s_in.c_str();
size_t aSize;
if( ::mbsrtowcs_s(&aSize, NULL, 0, &cs, 0, NULL) != 0)
{
throw std::exception("Cannot convert string");
}
std::vector<wchar_t> aBuffer(aSize);
size_t aSizeSec;
if (::mbstowcs_s(&aSizeSec, &aBuffer[0], aSize, cs, aSize) != 0)
{
throw std::exception("Cannot convert string");
}
return std::wstring(&aBuffer[0], aSize - 1);
}
BOM(字节顺序标记),然后您检查以确定字节顺序。否则,最好知道字节顺序,即最低有效或最高有效字节排在第一位。如果您不知道字节顺序并且没有 BOM,那么您只需要尝试一个或两个并应用一些统计测试和/或涉及人类决策者 (HDM)。
假设这个小字节序字节顺序,即最低有效字节优先。
然后对于每对字节,例如
w.push_back( (UnsignedChar( s[2*i + 1] ) << 8u) | UnsignedChar( s[2*i] ) );
其中w
是std::wstring
,i
是宽字符<s.length()/2
的索引,UnsignedChar
是unsigned char
的typedef
,s
是保存数据的std::string
,8是每字节的位数,即你必须假设或静态断言<limits.h>
头的CHAR_BITS
是8。>
您已将一系列表示 UTF-16 编码字符串的字节粘贴到std::string
中。大概您正在执行类似反序列化表示 UTF-16 的字节的操作,并且用于检索要反序列化的字节的 API 指定了 std::string。我不认为这是最好的设计,但您将处理将其转换为 wstring,就像处理将字节转换为浮点数或其他任何东西一样;验证字节缓冲区,然后将其强制转换:
char c[] = " a bxd8x3dxdcx7f";
std::string buf(std::begin(c),std::end(c));
assert(0==buf.size()%2);
std::wstring utf16(reinterpret_cast<wchar_t const *>(buf.data()),buf.size()/sizeof(wchar_t));
// also validate that each code unit is legal, and that there are no isolated surrogates
要记住的事项:
- 此强制转换假定wchar_t为 16 位,而大多数平台使用 32 位wchar_t。
- 为了有用,您的 API 需要能够将wchar_t字符串视为 UTF-16,因为这是为 wchar_t* 指定的平台编码,或者因为 API 只是遵循该约定。
- 此强制转换假定数据与计算机的字节序匹配。否则,您必须交换字符串中的每个 UTF-16 代码单元。在 UTF-16 编码方案下,如果初始字节不是 0xFF0xFE 或 0xFE0xFF,并且在没有更高级别的协议的情况下,则 UTF-16 编码使用大端编码。
- std::begin(), std::end() 和 string::d ata() 是 C++11
* UTF-16 实际上不符合C++语言对wchar_t编码的要求,但有些平台无论如何都会使用它。这会导致某些标准 API 出现问题,这些 API 应该处理代码点,但不能仅仅因为表示 UTF-16 代码单元的wchar_t不能表示平台的所有代码点。
这是一个不依赖于平台特定细节的实现,只需要wchar_t足够大以容纳 UTF-16 代码单元,并且每个字符正好包含 8 位 UTF-16 代码单元。不过,它实际上并没有验证 UTF-16 数据。
#include <string>
#include <cassert>
#include <iterator>
#include <algorithm>
#include <iostream>
enum class endian {
big,little,unknown
};
std::wstring deserialize_utf16be(std::string const &s) {
assert(0==s.size()%2);
std::wstring ws;
for(size_t i=0;i<s.size();++i)
if(i%2)
ws.back() = ws.back() | ((unsigned char)s[i] & 0xFF);
else
ws.push_back(((unsigned char)s[i] & 0xFF) << 8);
return ws;
}
std::wstring deserialize_utf16le(std::string const &s) {
assert(0==s.size()%2);
std::wstring ws;
for(size_t i=0;i<s.size();++i)
if(i%2)
ws.back() = ws.back() | (((unsigned char)s[i] & 0xFF) << 8);
else
ws.push_back((unsigned char)s[i] & 0xFF);
return ws;
}
std::wstring deserialize_utf16(std::string s, endian e=endian::unknown) {
static_assert(std::numeric_limits<wchar_t>::max() >= 0xFFFF,"wchar_t must be large enough to hold UTF-16 code units");
static_assert(CHAR_BIT>=8,"char must hold 8 bits of UTF-16 code units");
assert(0==s.size()%2);
if(endian::big == e)
return deserialize_utf16be(s);
if(endian::little == e)
return deserialize_utf16le(s);
if(2<=s.size() && ((unsigned char)s[0])==0xFF && ((unsigned char)s[1])==0xFE)
return deserialize_utf16le(s.substr(2));
if(2<=s.size() && ((unsigned char)s[0])==0xfe && ((unsigned char)s[1])==0xff)
return deserialize_utf16be(s.substr(2));
return deserialize_utf16be(s);
}
int main() {
char c[] = "xFFxFEx61 b x3dxd8x7fxdc";
std::string buf(std::begin(c),std::end(c)-1);
std::wstring utf16 = deserialize_utf16(buf);
std::cout << std::hex;
std::copy(begin(utf16),end(utf16),std::ostream_iterator<int>(std::cout," "));
std::cout << "n";
}
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- std::ofstream 作为类成员删除复制构造函数?
- 使用 memcpy() 复制到 std::chrono::milliseconds 会给出错误 -Werror=clas
- 在什么条件下使用 std::memcpy 在对象之间复制是安全的?
- 创建一个没有复制构造函数的类的 std::vector 的 std::vector
- 在 lambda 中锁定 std::shared_ptr 的复制操作
- std::p ackaged_task 应该删除带有 const 参数的复制 c'tor
- std::元组分配和复制/移动异常保证
- 转发复制的 std::tuple
- 使用std ::复制复制阵列时获取细分故障
- 将std ::复制转换为std :: memcpy不起作用
- STD ::复制在调试构建中失败
- 将指针而不是迭代器传递到std ::复制
- memcpy或std ::复制我的特定应用程序
- 我可以使用STD ::复制将数据的位模式从整数向量复制到一系列未签名的字符
- C++:std::复制失败,出现访问冲突读取位置错误
- 为什么memcpy无法复制特征矩阵数据,但std::复制成功
- std::复制钩子
- c++ std::复制结果不同于字符串构造函数
- C++11 std::复制内部函数