libxml2 xmlChar * to std::wstring

libxml2 xmlChar * to std::wstring

本文关键字:wstring std to xmlChar libxml2      更新时间:2023-10-16

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,则不会那么混乱,但我认为它会更清楚,因为我同时拥有charLengthwcharLength。至于代码的正确性,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_utf8std::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_tstd::wstring这是一个坏主意,除非你正在调用Windows API。

  1. xmlStrlen()不做你认为它做什么。它计算字符串中UTF-8代码单元(也就是字节)的数量。它不计算字符的数量。

  2. 无论如何,计数字符将无法移植地为wchar_t数组提供正确的大小。所以xmlStrlen()不仅没有做你认为它能做的事情,你想要的也不是正确的事情。问题是wchar_t的编码因平台而异,这使得它对可移植代码100%无用。

  3. mbtowcs()函数依赖于语言环境。只有当区域设置是UTF-8区域设置时,它才会从UTF-8进行转换!

  4. 如果std::wstring构造函数抛出异常,这段代码将会泄漏内存

我的建议:

  1. 尽可能使用UTF-8。 wchar_t兔子洞是很多额外的工作没有的好处(除了能够使Windows API调用)。

  2. 如果需要UTF-32,则使用std::u32string。请记住,wstring具有与平台相关的编码:它可以是可变长度编码(Windows)或固定长度编码(Linux, OS X)。

  3. 如果你绝对必须有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;
        }
    }
    
  4. 如果你绝对必须有wchar_t,而你不是在Windows上,使用iconv()(参见man 3 iconv, man 3 iconv_openman 3 iconv_close的手册)。您可以指定"WCHAR_T"作为iconv()的编码之一。

记住:你可能不需要wchar_tstd::wstringwchar_t可移植的功能是无用的,使它有用也是不可移植的。

add

# include & lt;提高/locale.hpp>

  1. 将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;
    
    它对我有用,祝你好运。