簡體   English   中英

libxml2 xmlChar *到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例程。 我想知道將xmlChar *轉換為C ++ 11中的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;
}

編輯:只是一個FYI,我非常清楚xmlStrlen返回的內容; 它是用於存儲字符串的xmlChar的數量; 我知道這不是字符數,而是unsigned char的數量。 如果我將它命名為byteLength ,那本來就不那么令人困惑了,但我認為它會更加清晰,因為我有charLengthwcharLength 至於代碼的正確性,寬緩沖區將大於或等於保持緩沖區所需的大小,總是(我相信)。 因為需要比wide_t更多空間的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所以你不必處理locales:

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 iconvman 3 iconv_openman 3 iconv_close手冊)。 您可以將"WCHAR_T"指定為iconv()的編碼之一。

記住:你可能不想要wchar_tstd::wstring 什么wchar_t可以移植是沒有用的,並使它有用是不可移植的。 這就是生活。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM