libxml2 xmlChar * to std::wstring
libxml2 xmlChar * to std::wstring
libxml2
似乎将其所有字符串都存储在UTF-8中,如xmlChar *
。
/**
* xmlChar:
*
* This is a basic byte in an UTF-8 encoded string.
* It's unsigned allowing to pinpoint case where char * are assigned
* to xmlChar * (possibly making serialization back impossible).
*/
typedef unsigned char xmlChar;
由于libxml2
是一个C库,因此没有提供从xmlChar *
中获取std::wstring
的例程。我想知道在c++ 11中将xmlChar *
转换为std::wstring
的谨慎的方式是否使用mbstowcs C函数,通过这样的东西(正在进行的工作):
std::wstring xmlCharToWideString(const xmlChar *xmlString) {
if(!xmlString){abort();} //provided string was null
int charLength = xmlStrlen(xmlString); //excludes null terminator
wchar_t *wideBuffer = new wchar_t[charLength];
size_t wcharLength = mbstowcs(wideBuffer, (const char *)xmlString, charLength);
if(wcharLength == (size_t)(-1)){abort();} //mbstowcs failed
std::wstring wideString(wideBuffer, wcharLength);
delete[] wideBuffer;
return wideString;
}
编辑:仅供参考,我非常清楚xmlStrlen
返回什么;它是用来存储字符串的xmlChar
的编号;我知道这不是字符的数量,而是unsigned char
的数量。如果我将其命名为byteLength
,则不会那么混乱,但我认为它会更清楚,因为我同时拥有charLength
和wcharLength
。至于代码的正确性,wideBuffer将大于或等于所需的大小来保存缓冲区,总是(我相信)。因为需要比wide_t
更多空间的字符将被截断(我认为)。
xmlStrlen()
返回xmlChar*
字符串中UTF-8编码码单元的个数。这与转换数据时所需的wchar_t
编码码单元的数量不同,因此不要使用xmlStrlen()
来分配wchar_t
字符串的大小。您需要调用std::mbtowc()
一次以获得正确的长度,然后分配内存,并再次调用mbtowc()
来填充内存。您还必须使用std::setlocale()
来告诉mbtowc()
使用UTF-8(乱弄区域设置可能不是一个好主意,特别是涉及多个线程时)。例如:
std::wstring xmlCharToWideString(const xmlChar *xmlString)
{
if (!xmlString) { abort(); } //provided string was null
std::wstring wideString;
int charLength = xmlStrlen(xmlString);
if (charLength > 0)
{
char *origLocale = setlocale(LC_CTYPE, NULL);
setlocale(LC_CTYPE, "en_US.UTF-8");
size_t wcharLength = mbtowc(NULL, (const char*) xmlString, charLength); //excludes null terminator
if (wcharLength != (size_t)(-1))
{
wideString.resize(wcharLength);
mbtowc(&wideString[0], (const char*) xmlString, charLength);
}
setlocale(LC_CTYPE, origLocale);
if (wcharLength == (size_t)(-1)) { abort(); } //mbstowcs failed
}
return wideString;
}
一个更好的选择,因为你提到了c++ 11,是使用std::codecvt_utf8
和std::wstring_convert
来代替,这样你就不必处理区域设置了:
std::wstring xmlCharToWideString(const xmlChar *xmlString)
{
if (!xmlString) { abort(); } //provided string was null
try
{
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> conv;
return conv.from_bytes((const char*)xmlString);
}
catch(const std::range_error& e)
{
abort(); //wstring_convert failed
}
}
另一种选择是使用实际的Unicode库,如ICU或ICONV,来处理Unicode转换。
这段代码中有一些问题,除了使用wchar_t
和std::wstring
这是一个坏主意,除非你正在调用Windows API。
-
xmlStrlen()
不做你认为它做什么。它计算字符串中UTF-8代码单元(也就是字节)的数量。它不计算字符的数量。 -
无论如何,计数字符将无法移植地为
wchar_t
数组提供正确的大小。所以xmlStrlen()
不仅没有做你认为它能做的事情,你想要的也不是正确的事情。问题是wchar_t
的编码因平台而异,这使得它对可移植代码100%无用。 -
mbtowcs()
函数依赖于语言环境。只有当区域设置是UTF-8区域设置时,它才会从UTF-8进行转换! -
如果
std::wstring
构造函数抛出异常,这段代码将会泄漏内存
我的建议:
-
尽可能使用UTF-8。
wchar_t
兔子洞是很多额外的工作没有的好处(除了能够使Windows API调用)。 -
如果需要UTF-32,则使用
std::u32string
。请记住,wstring
具有与平台相关的编码:它可以是可变长度编码(Windows)或固定长度编码(Linux, OS X)。 -
如果你绝对必须有
wchar_t
,那么很有可能你是在Windows上。以下是在Windows上的操作方法:std::wstring utf8_to_wstring(const char *utf8) { size_t utf8len = std::strlen(utf8); int wclen = MultiByteToWideChar( CP_UTF8, 0, utf8, utf8len, NULL, 0); wchar_t *wc = NULL; try { wc = new wchar_t[wclen]; MultiByteToWideChar( CP_UTF8, 0, utf8, utf8len, wc, wclen); std::wstring wstr(wc, wclen); delete[] wc; wc = NULL; return wstr; } catch (std::exception &) { if (wc) delete[] wc; } }
-
如果你绝对必须有
wchar_t
,而你不是在Windows上,使用iconv()
(参见man 3 iconv
,man 3 iconv_open
和man 3 iconv_close
的手册)。您可以指定"WCHAR_T"
作为iconv()
的编码之一。
记住:你可能不需要wchar_t
或std::wstring
。wchar_t
可移植的功能是无用的,使它有用也是不可移植的。
add
# include & lt;提高/locale.hpp>
- 将xmlChar*转换为字符串
std:: string strGbk ((char *)节点);
- 将字符串转换为wstring
std::string strGbk = ";
std::wstring wstr = boost::locale::conv::to_utf<wchar_t>(strGbk, "gbk");
std::cout << strGbk << std::endl;
std::wcout << wstr. << std::endl;
- 它对我有用,祝你好运。
- 将日语 wstring 转换为 std::string
- -fshort-wchar 和 std::wstring - 分段错误
- 如何将std::wstring转换为char const[]
- 将utf16宽std::wstring转换为utf8窄std::string以获得罕见字符时出现问题
- 找不到 std::wstring 中存在的wchar_t
- 将 std::string 转换为具有特殊字符的 FString (TCHAR / wstring)
- 将整数附加到 std::wstring 会给出错误
- 如何从 LPWSTR** 转换为 std::vector<std::wstring>
- std::vector<std::wstring> 移动/重新分配内部 wstring.data() 合法吗?
- 使用STD :: WSTRING或WCHAR_T登录
- 从 std::wstring 转换为 jstring
- UTF8 数据到 std::string 或 std::wstring
- 将 std::u16string 转换为 std::wstring,无需复制
- 如何通过 std::unordered_map<std::wstring, T> 中的 std::wstring_view 类型的键查找?
- 从相同的硬编码字符串文字初始化std::string和std::wstring
- C++:为什么在 #include 之前调用 std::wstring::begin() 会导致<vector>此代码中的编译器错误?
- C++ DLL 返回指向 std::list<std::wstring 的指针>
- std::wstring中ASCII符号的字节表示,具有不同的语言环境
- std::wstring 和 LOGFONT 重载冲突 - 为什么?
- Custom Stringstream - Convert std::wstring & std::string