International Components for Unicode (ICU)

Unicode (ICU) 的国际组件是一组成熟且广泛使用的开源全球化 API。 ICU 利用 Unicode 庞大的通用区域设置数据存储库 (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 创意者更新中,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) 。

入门

需要遵循三个main步骤: (Windows 10 创意者更新或更高版本的)

  1. 应用程序需要面向版本 1703 (创意者更新) 或更高版本Windows 10。

  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)之前, (见下图) 。 否则,链接器将链接到 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);
}