Rust国际化组件库icu_capi的使用:Unicode文本处理、日期格式化和区域敏感操作的C语言绑定

Rust国际化组件库icu_capi的使用:Unicode文本处理、日期格式化和区域敏感操作的C语言绑定

概述

icu_capi是ICU4X项目的C语言绑定,提供了Unicode文本处理、日期格式化和区域敏感操作等国际化功能。这个crate包含了extern "C" FFI接口以及通过Diplomat生成的C、C++、Dart、JavaScript和TypeScript绑定。

特性

  • 兼容no_std环境,但需要分配器支持
  • 提供稳定的C API接口(在同一个主要semver版本中保持稳定)
  • 支持多种编程语言的绑定

安装

在Cargo.toml中添加依赖:

icu_capi = "2.0.2"

或者运行命令:

cargo add icu_capi

使用示例

Unicode文本处理示例

use icu_capi::data_provider::StaticDataProvider;
use icu_capi::normalizer::UCharNormalizer;

// 创建静态数据提供者
let provider = StaticDataProvider::try_new_default().unwrap();

// 创建Unicode规范化器(NFC形式)
let normalizer = UCharNormalizer::try_new_nfc(&provider).unwrap();

// 输入文本
let input = "Café".as_bytes();

// 规范化文本
let mut output = Vec::new();
normalizer.normalize_utf8(input, &mut output).unwrap();

println!("Normalized: {}", String::from_utf8(output).unwrap());

日期格式化示例

use icu_capi::calendar::Gregorian;
use icu_capi::datetime::DateTimeFormat;
use icu_capi::data_provider::StaticDataProvider;
use icu_capi::locale::Locale;

// 创建静态数据提供者
let provider = StaticDataProvider::try_new_default().unwrap();

// 设置区域(美国英语)
let locale = Locale::try_from_bytes(b"en-US").unwrap();

// 创建日期格式化器
let options = DateTimeFormat::try_new_default_date(&provider, &locale).unwrap();

// 创建日期(2023年6月15日)
let date = Gregorian::try_new_date(2023, 6, 15).unwrap();

// 格式化日期
let mut output = Vec::new();
options.format_to_write(&mut output, &date).unwrap();

println!("Formatted date: {}", String::from_utf8(output).unwrap());

区域敏感操作示例

use icu_capi::collator::Collator;
use icu_capi::data_provider::StaticDataProvider;
use icu_capi::locale::Locale;

// 创建静态数据提供者
let provider = StaticDataProvider::try_new_default().unwrap();

// 设置区域(德语-德国)
let locale = Locale::try_from_bytes(b"de-DE").unwrap();

// 创建排序器
let collator = Collator::try_new(&provider, &locale).unwrap();

// 比较字符串(德语特殊字符ä与z比较)
let result = collator.compare(b"ä", b"z").unwrap();
println!("Comparison result: {}", result);

注意事项

  • 虽然这个crate的类型是公开的,但其API不打算直接从Rust使用
  • C API接口在同一主要semver版本中是稳定的
  • no_std环境下使用时,需要启用looping_panic_handlerlibc_alloc特性,或者自定义分配器/panic处理程序

完整示例

以下是一个完整的示例,展示如何使用icu_capi进行Unicode文本规范化、日期格式化和区域敏感排序:

use icu_capi::{
    calendar::Gregorian,
    collator::Collator,
    data_provider::StaticDataProvider,
    datetime::DateTimeFormat,
    locale::Locale,
    normalizer::UCharNormalizer,
};

fn main() {
    // 初始化数据提供者
    let provider = StaticDataProvider::try_new_default().unwrap();
    
    // 示例1: Unicode文本规范化
    let normalizer = UCharNormalizer::try_new_nfc(&provider).unwrap();
    let input = "Café".as_bytes();
    let mut normalized = Vec::new();
    normalizer.normalize_utf8(input, &mut normalized).unwrap();
    println!("Normalized text: {}", String::from_utf8(normalized).unwrap());
    
    // 示例2: 日期格式化
    let locale = Locale::try_from_bytes(b"en-US").unwrap();
    let date_format = DateTimeFormat::try_new_default_date(&provider, &locale).unwrap();
    let date = Gregorian::try_new_date(2023, 6, 15).unwrap();
    let mut formatted_date = Vec::new();
    date_format.format_to_write(&mut formatted_date, &date).unwrap();
    println!("Formatted date: {}", String::from_utf8(formatted_date).unwrap());
    
    // 示例3: 区域敏感排序
    let german_locale = Locale::try_from_bytes(b"de-DE").unwrap();
    let collator = Collator::try_new(&provider, &german_locale).unwrap();
    let comparison = collator.compare(b"ä", b"z").unwrap();
    println!("German comparison (ä vs z): {}", comparison);
}

这个示例展示了icu_capi的主要功能:

  1. Unicode文本规范化(NFC形式)
  2. 按照美国英语格式格式化日期
  3. 按照德语规则比较字符串

注意在实际使用时,需要根据具体需求调整区域设置和选项参数。


1 回复

Rust国际化组件库icu_capi的使用指南

概述

icu_capi是Rust中用于国际化和本地化操作的C语言绑定库,它基于ICU(International Components for Unicode)库,提供了强大的Unicode文本处理、日期格式化和区域敏感操作功能。

主要功能

  1. Unicode文本处理
  2. 日期和时间格式化
  3. 区域敏感操作(排序、数字格式化等)
  4. 字符集转换
  5. 复数规则处理

安装

在Cargo.toml中添加依赖:

[dependencies]
icu_capi = "0.7"

基本使用方法

1. Unicode文本处理

use icu_capi::normalizer::*;
use std::ffi::CString;

fn main() {
    // 创建规范化器
    let normalizer = unsafe { unorm2_getNFCInstance(std::ptr::null_mut()) };
    
    // 要规范化的字符串
    let input = CString::new("Café").unwrap();
    let mut output = [0u8; 32];
    
    // 执行规范化
    let status = unsafe {
        unorm2_normalize(
            normalizer,
            input.as_ptr() as *const u16,
            input.as_bytes().len() as i32,
            output.as_mut_ptr() as *mut u16,
            32,
            std::ptr::null_mut(),
        )
    };
    
    if status.is_ok() {
        println!("Normalization successful");
    }
}

2. 日期格式化

use icu_capi::udat::*;
use icu_capi::uloc::*;
use std::ffi::CString;

fn main() {
    // 设置区域
    let locale = CString::new("en-US").unwrap();
    let loc = unsafe { uloc_open(locale.as_ptr(), std::ptr::null(), std::ptr::null_mut()) };
    
    // 创建日期格式化器
    let pattern = CString::new("yyyy-MM-dd").unwrap();
    let df = unsafe {
        udat_open(
            UDAT_PATTERN,
            UDAT_PATTERN,
            loc,
            std::ptr::null(),
            -1,
            pattern.as_ptr() as *const u16,
            pattern.as_bytes().len() as i32,
            std::ptr::null_mut(),
        )
    };
    
    // 格式化当前时间
    let mut buffer = [0u16; 64];
    let now = unsafe { udat_getNow() };
    let len = unsafe {
        udat_format(
            df,
            now,
            buffer.as_mut_ptr(),
            64,
            std::ptr::null(),
            std::ptr::null_mut(),
        )
    };
    
    if len > 0 {
        let formatted = String::from_utf16_lossy(&buffer[..len as usize]);
        println!("Formatted date: {}", formatted);
    }
    
    // 清理资源
    unsafe {
        udat_close(df);
        uloc_close(loc);
    }
}

3. 区域敏感操作(数字格式化)

use icu_capi::unum::*;
use icu_capi::uloc::*;
use std::ffi::CString;

fn main() {
    // 设置区域
    let locale = CString::new("fr-FR").unwrap();
    let loc = unsafe { uloc_open(locale.as_ptr(), std::ptr::null(), std::ptr::null_mut()) };
    
    // 创建数字格式化器
    let nf = unsafe { unum_open(UNUM_DECIMAL, std::ptr::null(), -1, loc, std::ptr::null(), std::ptr::null_mut()) };
    
    // 格式化数字
    let number = 1234567.89;
    let mut buffer = [0u16; 64];
    let len = unsafe {
        unum_formatDouble(
            nf,
            number,
            buffer.as_mut_ptr(),
            64,
            std::ptr::null(),
            std::ptr::null_mut(),
        )
    };
    
    if len > 0 {
        let formatted = String::from_utf16_lossy(&buffer[..len as usize]);
        println!("Formatted number (French): {}", formatted); // 输出 "1 234 567,89"
    }
    
    // 清理资源
    unsafe {
        unum_close(nf);
        uloc_close(loc);
    }
}

完整示例demo

下面是一个综合使用icu_capi的完整示例,展示了文本规范化、日期格式化和数字格式化的组合使用:

use icu_capi::{normalizer::*, udat::*, unum::*, uloc::*};
use std::ffi::CString;

fn main() {
    // ==== 第一部分:Unicode文本规范化 ====
    println!("=== Unicode文本规范化 ===");
    
    // 创建NFC规范化器
    let normalizer = unsafe { unorm2_getNFCInstance(std::ptr::null_mut()) };
    let input = CString::new("Café").unwrap();
    let mut output = [0u8; 32];
    
    // 执行规范化
    let status = unsafe {
        unorm2_normalize(
            normalizer,
            input.as_ptr() as *const u16,
            input.as_bytes().len() as i32,
            output.as_mut_ptr() as *mut u16,
            32,
            std::ptr::null_mut(),
        )
    };
    
    if status.is_ok() {
        println!("文本规范化成功");
    }

    // ==== 第二部分:日期格式化 ====
    println!("\n=== 日期格式化 ===");
    
    // 设置英文(美国)区域
    let locale_en = CString::new("en-US").unwrap();
    let loc_en = unsafe { uloc_open(locale_en.as_ptr(), std::ptr::null(), std::ptr::null_mut()) };
    
    // 创建日期格式化器
    let pattern = CString::new("yyyy-MM-dd HH:mm:ss").unwrap();
    let df = unsafe {
        udat_open(
            UDAT_PATTERN,
            UDAT_PATTERN,
            loc_en,
            std::ptr::null(),
            -1,
            pattern.as_ptr() as *const u16,
            pattern.as_bytes().len() as i32,
            std::ptr::null_mut(),
        )
    };
    
    // 格式化当前时间
    let mut date_buffer = [0u16; 64];
    let now = unsafe { udat_getNow() };
    let len = unsafe {
        udat_format(
            df,
            now,
            date_buffer.as_mut_ptr(),
            64,
            std::ptr::null(),
            std::ptr::null_mut(),
        )
    };
    
    if len > 0 {
        let formatted = String::from_utf16_lossy(&date_buffer[..len as usize]);
        println!("英文日期格式: {}", formatted);
    }
    
    // ==== 第三部分:数字格式化 ====
    println!("\n=== 数字格式化 ===");
    
    // 设置法语(法国)区域
    let locale_fr = CString::new("fr-FR").unwrap();
    let loc_fr = unsafe { uloc_open(locale_fr.as_ptr(), std::ptr::null(), std::ptr::null_mut()) };
    
    // 创建数字格式化器
    let nf = unsafe { unum_open(UNUM_DECIMAL, std::ptr::null(), -1, loc_fr, std::ptr::null(), std::ptr::null_mut()) };
    
    // 格式化数字
    let number = 1234567.89;
    let mut num_buffer = [0u16; 64];
    let len = unsafe {
        unum_formatDouble(
            nf,
            number,
            num_buffer.as_mut_ptr(),
            64,
            std::ptr::null(),
            std::ptr::null_mut(),
        )
    };
    
    if len > 0 {
        let formatted = String::from_utf16_lossy(&num_buffer[..len as usize]);
        println!("法文数字格式: {}", formatted); // 输出 "1 234 567,89"
    }
    
    // ==== 清理资源 ====
    unsafe {
        // 释放文本规范化相关资源
        // (注意:unorm2_getNFCInstance返回的是共享实例,不需要关闭)
        
        // 释放日期格式化相关资源
        udat_close(df);
        uloc_close(loc_en);
        
        // 释放数字格式化相关资源
        unum_close(nf);
        uloc_close(loc_fr);
    }
}

注意事项

  1. 大多数ICU C API函数需要手动管理内存,确保正确释放资源
  2. 错误处理通过返回的UErrorCode进行
  3. 字符串通常以UTF-16格式处理
  4. 在多线程环境中使用时需要注意线程安全性

高级功能

icu_capi还支持更高级的功能,如:

  • 双向文本处理(阿拉伯语、希伯来语等)
  • 断词和断行
  • 转换器(字符编码转换)
  • 复数规则和消息格式化

性能建议

  1. 重用格式化器实例,避免频繁创建和销毁
  2. 对于固定模式,考虑预编译模式
  3. 使用缓冲区重用技术减少内存分配

通过icu_capi,Rust开发者可以方便地利用ICU库的强大国际化功能,同时保持与C语言生态系统的互操作性。

回到顶部