2012-10-26 101 views
10

我試圖在Windows中實現文本支持,以便稍後也轉移到Linux平臺。以統一的方式支持國際語言是理想的,但在考慮這兩個平臺時似乎並不容易完成。我花了相當多的時間閱讀UNICODE,UTF-8(以及其他編碼),widechars等等,這裏是我到目前爲止瞭解的內容:UNICODE,UTF-8和Windows混亂

UNICODE作爲標準描述了集合可映射的字符以及它們出現的順序。我將其稱爲「what」:UNICODE指定什麼將可用。

UTF-8(和其他編碼)指定如何:每個字符將如何以二進制格式表示。

現在,在windows上,他們選擇了最初的UCS-2編碼,但是未能滿足要求,所以UTF-16就是他們所擁有的,在必要時也是多字符。

因此,這裏的delemma:

  1. 的Windows內部只做UTF-16,所以如果你想支持你不得不轉換爲其widechar版本,以便使用OS據此呼籲國際字符。似乎沒有任何支持使用多字節UTF-8字符串來調用諸如CreateFileA()之類的東西,並使它看起來正確。它是否正確?
  2. 在C語言中,有一些支持多字節的函數(_mbscat,_mbscpy等),但是在windows上,字符類型被定義爲unsigned char *。鑑於_mbs系列函數不是一個完整的集合(例如,沒有_mbstol將多字節字符串轉換爲long),您不得不使用某些char *版本的運行時函數,由於這些函數之間的有符號/無符號類型差異而導致編譯器問題。有人甚至使用這些?你只是做了一堆鑄造來解決錯誤?
  3. 在C++中,std :: string有迭代器,但這些都是基於char_type,而不是代碼點。所以如果我在一個std :: string :: iterator上做一個++,我得到下一個char_type,而不是下一個代碼點。同樣,如果你調用std :: string :: operator [],你會得到一個char_type的引用,這個引用很有可能不是一個完整的代碼點。那麼如何通過代碼來迭代std :: string? (C具有_mbsinc()函數)。
+1

不是「必要時需要多字節」。這只是「多字節」。在開始處理它之前,您不知道它是否「必要」。 –

+0

這是關於這個主題的[我的帖子](http://stackoverflow.com/questions/6300804/wchars-encodings-standards-and-portability)也許這是你感興趣的。對於(3),將數據轉換爲UTF-32(理想情況下存儲在char32_t中),然後代碼指向相同的字符串元素。 –

+3

請記住,代碼點迭代Unicode字符串的合法理由很少,因爲字形可能由多個代碼點表示(每個代碼點可以是UTF-8或UTF-16中的多個代碼單元,但對於許多實際目的都是兩次相同的問題)。規範化是一個合法的原因,編碼爲UTF-8是另一個合理的原因,但這些都是您可以使用庫的事情。 –

回答

6
  1. 正確。您將爲您的Windows API調用將UTF-8轉換爲UTF-16。

  2. 你們中的大多數會使用常規的字符串函數爲UTF-8時 - strlenstrcpy(益),snprintfstrtol。他們將使用UTF-8字符正常工作。對於UTF-8使用char *,否則您將不得不施放所有內容。

    請注意,像_mbstowcs這樣的下劃線版本不是標準的,它們通常不帶下劃線地命名,如mbstowcs

  3. 很難想出你真的想在Unicode字符串上使用operator[]的例子,我的建議是遠離它。同樣,遍歷字符串具有令人驚訝的幾個用途:

    • 如果您解析字符串(例如,字符串是C或JavaScript代碼,也許你想語法高亮顯示),那麼你可以完成大部分的工作字節逐字節並忽略多字節方面。

    • 如果您正在進行搜索,您也將逐字節地執行此操作(但請記住先進行歸一化)。

    • 如果您正在尋找分詞符或字形集羣邊界,您將需要使用像ICU這樣的庫。該算法並不簡單。

    • 最後,您總是可以將一大塊文本轉換爲UTF-32,並以此方式處理它。如果你正在實現任何Unicode算法,比如整理或打破,我認爲這是最好的選擇。

    參見:C++ iterate or split UTF-8 string into array of symbols?

2
  1. 的Windows內部只做UTF-16,所以如果你想支持你不得不轉換爲其widechar版本,以便使用OS據此呼籲國際字符。似乎沒有任何支持使用多字節UTF-8字符串來調用諸如CreateFileA()之類的東西,並使它看起來正確。它是否正確?

是的,這是正確的。 *A函數變體根據當前活動的代碼頁(在美國和西歐的大多數計算機上是Windows-1252,但通常可能是其他代碼頁)解釋字符串參數並將它們轉換爲UTF-16。有一個UTF-8代碼頁,但是AFAIK沒有以編程方式設置活動代碼頁(有GetACP獲得活動代碼頁,但不對應SetACP)的方法。

  1. 在C中,有一些多字節支持功能(_mbscat,_mbscpy等),然而,在Windows中,字符類型被定義爲無符號字符*爲這些功能。鑑於_mbs系列函數不是一個完整的集合(例如,沒有_mbstol將多字節字符串轉換爲long),您不得不使用某些char *版本的運行時函數,由於這些函數之間的有符號/無符號類型差異而導致編譯器問題。有人甚至使用這些?你只是做了一堆鑄造來解決錯誤?

mbs*家庭的功能幾乎從來沒有使用過,在我的經驗。隨着mbstowcsmbsrtowcs,和mbsinit例外,這些功能都沒有標準C.

  1. 在C++中,的std :: string具有迭代器,但這些都是基於char_type,而不是代碼點。所以如果我在一個std :: string :: iterator上做一個++,我得到下一個char_type,而不是下一個代碼點。同樣,如果你調用std :: string :: operator [],你會得到一個char_type的引用,這個引用很有可能不是一個完整的代碼點。那麼如何通過代碼來迭代std :: string? (C具有_mbsinc()函數)。

我認爲mbrtowc(3)將在這裏進行解碼的多字節字符串的單碼點的最佳選擇。總體而言,我認爲跨平臺Unicode兼容性的最佳策略是使用單字節字符在UTF-8內部完成所有內容。當您需要調用Windows API函數時,將其轉換爲UTF-16並始終調用*W變體。大多數非Windows平臺已經使用UTF-8,因此可以使用這些功能。

+0

不幸的是,'mbrtowc'不能解碼Windows上的代碼點。 –

9

只是做UTF-8

有很多支持庫爲UTF-8在每plaftorm,也有一些是multiplaftorm了。正如您已經注意到的那樣,Win32中的UTF-16 API是有限且不一致的,因此最好將所有內容保存在UTF-8中,並最終轉換爲UTF-16。還有一些方便的用於Windows API的UTF-8包裝。

另外,在應用程序級別的文檔中,UTF-8越來越被接受爲標準。每個文本處理應用程序都可以接受UTF-8,或者最壞的情況是將它顯示爲「帶有一些dingbats的ASCII」,而只有少數應用程序支持UTF-16文檔,而那些不支持UTF-16文檔的應用程序則顯示爲「的空白!「

+0

+1恰恰是我剛剛輸入的內容...... – Damon

+2

+1,用於支持utf8everywhere.org的想法 –

+1

我會添加一個很好的參考,爲什麼UTF-8應該在任何地方使用http://utf8everywhere.org/ –