Unicode 的國際元件 (ICU)

Unicode (ICU) 國際元件是一組成熟且廣泛使用的開放原始碼全球化 API。 ICU 利用 Unicode 的龐大 Common Locale Data Repository (CLDR) 作為其資料庫,為軟體應用程式提供全球化支援。 ICU 可廣泛移植,可在所有平臺上提供應用程式相同的結果。

ICU 所提供的全球化 API 服務重點

  • 字碼頁轉換:將文字資料轉換成 Unicode,以及幾乎任何其他字元集或編碼方式。 ICU 的轉換資料表是以 IBM 在數十年來所收集的字元集資料為基礎,而且是在任何地方提供的最完整資料。
  • 定序:根據特定語言、地區或國家/地區的慣例和標準來比較字串。 ICU 的定序是以 Unicode 定序演算法為基礎,加上 CLDR 的地區設定特定比較規則。
  • 格式:根據所選地區設定的慣例,格式化數位、日期、時間和貨幣金額。 這包括將月份和日名稱翻譯成選取的語言、選擇適當的縮寫、正確排序欄位等等。此資料也來自通用地區設定資料存放庫。
  • 時間計算:除了傳統的西曆之外,還提供多種行事曆類型。 系統會提供一組完整的時區計算 API。
  • Unicode 支援:ICU 會密切追蹤 Unicode 標準,讓您輕鬆存取所有 Unicode 字元屬性、Unicode 正規化、大小寫折迭,以及其他 Unicode 標準所指定的基本作業。
  • 正則運算式:ICU 的正則運算式完全支援 Unicode,同時提供非常競爭的效能。
  • Bidi:支援處理文字,其中包含英文 () 和由右至左 (阿拉伯文或希伯來文) 資料的混合。

如需詳細資訊,您可以流覽 ICU 網站: http://site.icu-project.org/

概觀

在Windows 10 Creators Update中,ICU 已整合到 Windows 中,讓 C API 和資料可供公開存取。

重要

Windows 中的 ICU 版本只會公開 C API。 它不會公開任何 C++ API。 不幸的是,由於 C++ 中缺少穩定的 ABI,因此不可能公開 C++ API。

如需 ICU C API 的檔,請參閱這裡的官方 ICU 檔頁面: http://icu-project.org/apiref/icu4c/index.html#Module

Windows 中 ICU 程式庫變更的歷程記錄

版本 1703 (Creators Update)

ICU 程式庫會先新增至此版本中的 Windows 10 OS。 它已新增為:

  • 兩個系統 DLL:
    • icuuc.dll (這是 ICU「通用」程式庫)
    • icuin.dll( 這是 ICU 「i18n」 程式庫)
  • Windows 10 SDK 中的兩個標頭檔:
    • icucommon.h
    • icui18n.h
  • Windows 10 SDK 中的兩個匯入程式庫:
    • icuuc.lib
    • icuin.lib

版本 1709 (Fall Creators Update)

已新增合併標頭檔 icu.h,其中包含上述兩個標頭檔的內容, (icucommon.h 和 icui18n.h) ,也會將 的類型 UCHAR 變更為 char16_t

版本 1903 (2019 年 5 月更新)

已新增新的合併 DLL icu.dll,其中包含 「common」 和 「i18n」 程式庫。 此外,已將新的匯入程式庫新增至 Windows 10 SDK:icu.lib

接下來,不會將新的 API 新增至舊標頭 (icucommon.h 和 icui18n.h) 或舊匯入程式庫 (icuuc.lib 和 icuin.lib) 。 新的 API 只會新增至合併標頭 (icu.h) 和合併匯入程式庫 (icu.lib) 。

開始使用

有三個主要步驟要遵循: (Windows 10 Creators Update或更新版本)

  1. 您的應用程式需要以 Windows 10 版本 1703 (Creators Update) 或更高版本為目標。

  2. 在標頭中新增:

    #include <icucommon.h>
    #include <icui18n.h>
    

    在 Windows 10 版本 1709 和更新版本上,您應該改為包含合併的標頭:

    #include <icu.h>
    
  3. 連結至兩個程式庫:

    • icuuc.lib
    • icuin.lib

    在 Windows 10 1903 版和更新版本上,您應該改用合併的程式庫:

    • icu.lib

然後,您可以從您想要的這些程式庫呼叫任何 ICU C API。 (未公開任何 C++ API。)

重要

如果您使用舊版匯入程式庫 icuuc.lib 和 icuin.lib,請確定它們會列在像是 onecoreuap.lib 或 WindowsApp.lib 的 umbrella 程式庫之前, (請參閱下圖) 。 否則,連結器會連結至 icu.lib,這會導致嘗試在執行時間載入icu.dll。 該 DLL 只會從 1903 版開始出現。 因此,如果使用者在 1903 版 Windows 電腦上升級Windows 10 SDK,應用程式將無法載入並執行。 如需 Windows 中 ICU 程式庫的歷程記錄,請參閱 Windows 中 ICU 程式庫變更的歷程記錄

icu 範例

注意

  • 這是「所有平臺」的設定。
  • 若要讓 Win32 應用程式使用 ICU,他們必須先呼叫 CoInitializeEx 。 在 Windows 10 1903 版和更新版本上,可以使用合併的 ICU 程式庫 (icu.dll/icu.lib) ,您可以使用合併程式庫來省略 CoInitializeEx 呼叫。
  • 並非所有 ICU API 傳回的資料都會與 Windows OS 一致,因為此對齊工作仍在進行中。 

ICU 範例應用程式

範例程式碼片段

以下是說明在 C++ UWP 應用程式中使用 ICU API 的範例。 (它不是完整的獨立應用程式,而是呼叫 ICU 方法的範例。)

下列小型範例假設有一些 方法 ErrorMessageOutputMessage 會以某種方式將字串輸出給使用者。

// On Windows 10 Creators Update, include the following two headers. With Windows 10 Fall Creators Update and later, you can just include the single header <icu.h>.
#include <icucommon.h>
#include <icui18n.h>

void FormatDateTimeICU()
{
    UErrorCode status = U_ZERO_ERROR;

    // Create a ICU date formatter, using only the 'short date' style format.
    UDateFormat* dateFormatter = udat_open(UDAT_NONE, UDAT_SHORT, nullptr, nullptr, -1, nullptr, 0, &status);

    if (U_FAILURE(status))
    {
        ErrorMessage(L"Failed to create date formatter.");
        return;
    }

    // Get the current date and time.
    UDate currentDateTime = ucal_getNow();

    int32_t stringSize = 0;
    
    // Determine how large the formatted string from ICU would be.
    stringSize = udat_format(dateFormatter, currentDateTime, nullptr, 0, nullptr, &status);

    if (status == U_BUFFER_OVERFLOW_ERROR)
    {
        status = U_ZERO_ERROR;
        // Allocate space for the formatted string.
        auto dateString = std::make_unique<UChar[]>(stringSize + 1);

        // Format the date time into the string.
        udat_format(dateFormatter, currentDateTime, dateString.get(), stringSize + 1, nullptr, &status);

        if (U_FAILURE(status))
        {
            ErrorMessage(L"Failed to format the date time.");
            return;
        }

        // Output the formatted date time.
        OutputMessage(dateString.get());
    }
    else
    {
        ErrorMessage(L"An error occured while trying to determine the size of the formatted date time.");
        return;
    }

    // We need to close the ICU date formatter.
    udat_close(dateFormatter);
}