2010-01-10 122 views
17

我知道關於std::stringstd::wstring或類似的StackOverflow已經存在幾個問題,但他們都沒有提出完整的解決方案。在C++下處理Unicode字符串的最佳多平臺方式是什麼?

爲了獲得一個很好的答案,我應該明確要求:

  • 使用,必須在Windows,Mac OS X和Linux工作
  • 最小的努力爲轉換到/從特定平臺Unicode字符串CFStringRef,wchar_t *,char*爲UTF-8或其他類型,因爲它們是OS API所需的。備註:我不需要代碼頁轉換支持,因爲我希望在所有支持的操作系統上只使用Unicode兼容功能。
  • 如果需要一個外部庫,這個應該是開源並且在一個非常自由的許可下,如BSD但不是LGPL。
  • 能夠使用printf格式語法或類似。
  • 簡單的字符串分配/釋放方式
  • 性能並不是非常重要,因爲我認爲Unicode字符串僅用於應用程序UI。
  • 一些例子可能將不勝​​感激

我真的很感激,只有一個每答案提出的解決方案,這樣做的人會投票給他們的首選替代品。如果您有多個替代方案,請添加其他答案。

請指出確實爲你工作的東西

相關問題:

+2

你是什麼意思 「處理Unicode字符串」?你只是想要一些可以存儲一系列Unicode代碼點的東西嗎?正確處理文化特定歸類的東西?一些能夠處理規範和非規範形式的字符串的東西? – jalf 2010-01-10 17:27:56

+0

@jalf好點!我忘了提及我故意排除高級字符串用法,如字符串修改或規範化形式,排序。我認爲,爲了簡單起見,我只會使用這些字符串進行顯示(但我可能需要使用printf格式或字符串並置,但不會更多)。除此之外的任何內容都需要ICU或其他庫。 – sorin 2010-01-10 17:42:40

回答

5

同亞當·羅森菲爾德回答(+1),但我用UTFCPP代替。

+0

+1,有趣的圖書館,非常地道。 – avakar 2010-01-10 20:57:02

+0

對於內部表示,它與std :: wstring一樣正常工作。拿你的選擇。 – 2010-01-30 08:33:55

7

我會強烈建議使用UTF-8內部在你的應用程序,使用普通的舊char*std::string用於數據存儲。爲了與使用不同編碼(ASCII,UTF-16等)的API接口,我建議使用libiconv,它是根據LGPL許可的。

用法示例:

class TempWstring 
{ 
public: 
    TempWstring(const char *str) 
    { 
    assert(sUTF8toUTF16 != (iconv_t)-1); 
    size_t inBytesLeft = strlen(str); 
    size_t outBytesLeft = 2 * (inBytesLeft + 1); // worst case 
    mStr = new char[outBytesLeft]; 
    char *outBuf = mStr; 
    int result = iconv(sUTF8toUTF16, &str, &inBytesLeft, &outBuf, &outBytesLeft); 
    assert(result == 0 && inBytesLeft == 0); 
    } 

    ~TempWstring() 
    { 
    delete [] mStr; 
    } 

    const wchar_t *Str() const { return (wchar_t *)mStr; } 

    static void Init() 
    { 
    sUTF8toUTF16 = iconv_open("UTF-16LE", "UTF-8"); 
    assert(sUTF8toUTF16 != (iconv_t)-1); 
    } 

    static void Shutdown() 
    { 
    int err = iconv_close(sUTF8toUTF16); 
    assert(err == 0); 
    } 

private: 
    char *mStr; 

    static iconv_t sUTF8toUTF16; 
}; 

iconv_t TempWstring::sUTF8toUTF16 = (iconv_t)-1; 

// At program startup: 
TempWstring::Init(); 

// At program termination: 
TempWstring::Shutdown(); 

// Now, to convert a UTF-8 string to a UTF-16 string, just do this: 
TempWstring x("Entr\xc3\xa9""e"); // "Entrée" 
const wchar_t *ws = x.Str(); // valid until x goes out of scope 

// A less contrived example: 
HWND hwnd = CreateWindowW(L"class name", 
          TempWstring("UTF-8 window title").Str(), 
          dwStyle, x, y, width, height, parent, menu, hInstance, lpParam); 
+4

+1,我完全同意utf-8和'std :: string'。 – avakar 2010-01-10 17:24:18

+2

所以*每個*平凡的字符串操作都需要轉換? – 2010-01-10 18:44:09

+2

你的建議是採用與所有操作系統完全相反的方式。內部Win/Mac使用UTF-16(因爲它是固定大小(不是真的,但對於大多數實際用途而言)(實際上它的UCS-2,但不告訴任何人))。存儲以UTF-8完成。 – 2010-01-10 18:48:21

2

我最近在一個項目中決定使用std :: wstring作爲跨平臺項目,因爲「寬字符串是Unicode的,對不對?」這導致了一些令人頭痛的問題:

  • wstring中的標量值有多大?答:這取決於編譯器的實現。在Visual Studio(Win)中,它是16位。但在Xcode(Mac)中,它是32位。
  • 這導致了一個不幸的決定通過線路使用UTF-16進行通信。但是,哪個UTF-16?有兩種:UTF-16BE(big-endian)和UTF16-LE(小端)。不清楚這導致更多的錯誤。

當您處於平臺特定的代碼中時,使用平臺的本機表示與其API進行通信是有意義的。但對於跨平臺共享的任何代碼,或平臺之間的通信,請避免模糊不清,並使用UTF-8。

+0

哪些UTF-16通過線路很容易您只需確保BOM作爲第一個字符發送。接收層(上面的傳輸層然後根據需要重新安排消息,但我同意UTF-8用於傳輸更容易並且通常更緊湊(並且代碼轉換UTF-16 - > UTF-8是微不足道的) – 2010-01-10 18:51:21

+2

與傳輸一樣如果你使用的是UTF-8,存儲會更容易 – 2010-01-10 18:52:10

+1

我認爲*如果*你使用的是UTF-16,你應該堅持使用網絡永久性 - 這是大端的,不需要使任何協議變得更復雜 – sorin 2010-01-10 20:45:00

1

經驗法則:使用用於處理的本地平臺的Unicode形式(UTF-16或UTF-32),和UTF-8的數據交換(通信,存儲)。

如果所有本地API都使用UTF-16(例如在Windows中),將字符串作爲UTF-8意味着您必須將所有輸入轉換爲UTF-16,調用Win API,然後將答案轉換爲UTF-8。非常痛苦。

但如果主要問題是用戶界面,該字符串是簡單的問題。 更難的是UI框架。 爲此,我會推薦wxWidgets(http://www.wxWidgets.org)。支持許多平臺,成熟(17年,仍然非常活躍),原生小部件,Unicode,自由許可證。

1

我會去UTF16表示在存儲器和UTF-8或16上的硬盤或導線。主要原因:UTF16對每個「字母」都有固定的大小。這可以簡化使用絃線時的許多職責(se光,更換零件......)。

對於UTF-8的唯一原因是爲「西方/拉丁」字母減少存儲器使用量。您可以將此表示用於光盤存儲或通過網絡傳輸。它也有利於您在加載/保存到光盤/線路時不必擔心字節順序問題。

考慮到這些原因,我會去的std ::內部或wstring的 - 如果你的GUI庫提供了一個WideString的,使用(從QT喜歡的QString)。對於光盤存儲,我會爲平臺api編寫一個小平臺獨立包裝器。或者如果他們有可用於此轉換的平臺代碼,請查看unicode.org。


澄清:韓文/日文字母不是西方/拉丁文。日語是以漢字爲例。這就是我提到拉丁字符集的原因。


對於UTF-16不是1字符/ 2字節。這種假設只適用於基礎多語言平面上的字符(請參閱:http://en.wikipedia.org/wiki/UTF16)。仍然大多數UTF-16用戶都假定所有字符都在BMP上。如果您的應用程序無法保證,您可以切換到UTF32或切換到UTF8。

還是UTF-16被用於很多的API的上述原因(例如,Windows,QT,Java和.NET,wxWidgets的)

+4

UTF16沒有固定大小的每個字母 – 2010-01-11 08:22:51

+2

UTF-8還有其他好處,例如能夠由標準的C字符串函數處理 – 2010-01-11 08:27:54

+0

關於「減少西文/拉丁文字符的內存使用量」的提示:事情比看起來要複雜得多維基百科說:「例如,日文和韓文的UTF-8文章都是關於W如果以原始UTF-8版本保存爲UTF-16,ikipedia佔用更多空間「。 – 2010-01-11 08:54:44

相關問題