6个版本 (破坏性更新)
使用旧的Rust 2015
| 0.6.0 | 2017年9月22日 | 
|---|---|
| 0.5.0 | 2017年8月5日 | 
| 0.4.0 | 2017年6月23日 | 
| 0.2.0 | 2017年6月21日 | 
| 0.1.1 | 2017年6月20日 | 
#23 in #unic
5KB
62 行
UNIC:Rust的Unicode和国际化的组件
https://github.com/open-i18n/rust-unic
UNIC是一个开发Rust编程语言组件的项目,以提供高质量且易于使用的Unicode和国际化的数据算法库。换句话说,它就像Rust的ICU,完全用Rust编写,大部分在安全模式下编写,但在可能的情况下,也受益于不安全模式带来的性能提升。
请参阅UNIC变更日志以获取最新发布详情。
项目目标
UNIC的目标是提供访问Unicode和国际化的所有级别的功能,从Unicode字符属性开始,到处理文本的Unicode算法,再到基于Unicode通用区域数据仓库(CLDR)的更高级(基于区域设置)的过程。
根据需要,也实现了其他标准和最佳实践,如IETF RFCs。
项目状态
目前,UNIC正处于快速开发阶段:API在master分支上频繁更新,并且每个0.x版本之间将会有API破坏。请参阅公开问题以了解计划更改。
我们预计将在2018年发布1.0版本,并在之后维护稳定的API,可能每年进行一到两次API更新。
设计目标
- 
UNIC的主要目标是通过易于使用的API提供可靠的功能。因此,新添加的组件可能不会针对性能进行优化,但将有足够的测试来展示对标准的符合性,并举例说明用户如何使用它们来解决常见需求。 
- 
UNIC组件的下一个主要目标是性能和低二进制和内存占用。特别是,优化ASCII和其他常见情况下的运行时将鼓励适应,而无需担心减缓常规开发流程。 
- 
组件尽可能保证提供一致的数据和算法。通过跨组件测试来捕捉实现之间的任何不一致,而不减慢开发过程。 
组件及其组织
UNIC 组件 具有分层组织结构,从 unic 根开始,包含 主要组件。每个主要组件又可能包含一些 次要组件。
主要组件的 API 旨在为库的最终用户设计,并预期将进行广泛的文档编写,并附有代码示例。
与主要组件相反,次要组件作为高级组件的数据和算法的提供者,其 API 预期将更具性能,并且可能提供多种访问数据的方式。
UNIC 超组件
unic 超组件是一个包含所有 UNIC(主要)组件的集合,提供了一种方便的方式来访问所有功能,当需要所有或许多功能时,而不是逐个导入组件。此组件确保所有导入的组件在算法和数据上都是兼容的。
主要的代码示例和跨组件集成测试是在此组件下实现的。
主要组件
- 
unic-char:Unicode 字符工具。
- 
unic-ucd:Unicode 字符数据库(《UAX#44》)。
- 
unic-bidi:Unicode 双向算法(《UAX#9》)。
- 
unic-normal:Unicode 正规化形式(《UAX#15》)。
- 
unic-segment:Unicode 文本分段算法(《UAX#29》)。
- 
unic-idna:Unicode IDNA 兼容处理(《UTS#46》)。
- 
unic-emoji:Unicode 表情(《UTS#51》)。
应用
- unic-cli:UNIC 命令行工具
代码组织:组合仓库
以下是一些将这些组件组合在一起的原因
- 
更快的开发。实现新的 Unicode/i18n 组件通常依赖于其他(低级别)组件,而这些组件又可能需要调整——暴露新的 API、修复错误等,这些都可以在更少的周期和更短的时间内进行开发、测试和审查。 
- 
实施完整性。多个组件之间的依赖关系意味着组件需要在一定程度上相互一致。许多由较小部分组成的Unicode算法假设算法的所有部分都使用相同的Unicode数据版本。违反这一假设可能导致不一致和难以发现的错误。在一个组合存储库中,在开发过程中以及进行跨组件(集成)测试时,可以达到更好的完整性。 
- 
按需付费。小型组件(基本crate),仅依赖于它们所需的跨依赖,使用户只能将其项目消耗的内容引入。 
- 
共享引导。大量扩展Unicode/i18n功能依赖于将源Unicode/区域数据转换为目标编程语言的格式化格式。在组合存储库中,更容易维护这些引导工具,扩展覆盖范围,并使用更好的数据结构以提高效率。 
文档
- Unicode和Rust
- UNIC版本控制
- UNIC Unicode API
- UNIC API指南
- UNIC API参考(由docs.rs自动生成)
如何使用UNIC
在Cargo.toml
[dependencies]
unic = "0.9.0"  # This has Unicode 10.0.0 data and algorithms
以及在main.rs
extern crate unic;
use unic::ucd::common::is_alphanumeric;
use unic::bidi::BidiInfo;
use unic::normal::StrNormalForm;
use unic::segment::{GraphemeIndices, Graphemes, WordBoundIndices, WordBounds, Words};
use unic::ucd::normal::compose;
use unic::ucd::{is_cased, Age, BidiClass, CharAge, CharBidiClass, StrBidiClass, UnicodeVersion};
fn main() {
    // Age
    assert_eq!(Age::of('A').unwrap().actual(), UnicodeVersion { major: 1, minor: 1, micro: 0 });
    assert_eq!(Age::of('\u{A0000}'), None);
    assert_eq!(
        Age::of('\u{10FFFF}').unwrap().actual(),
        UnicodeVersion { major: 2, minor: 0, micro: 0 }
    );
    if let Some(age) = '🦊'.age() {
        assert_eq!(age.actual().major, 9);
        assert_eq!(age.actual().minor, 0);
        assert_eq!(age.actual().micro, 0);
    }
    // Bidi
    let text = concat![
        "א",
        "ב",
        "ג",
        "a",
        "b",
        "c",
    ];
    assert!(!text.has_bidi_explicit());
    assert!(text.has_rtl());
    assert!(text.has_ltr());
    assert_eq!(text.chars().nth(0).unwrap().bidi_class(), BidiClass::RightToLeft);
    assert!(!text.chars().nth(0).unwrap().is_ltr());
    assert!(text.chars().nth(0).unwrap().is_rtl());
    assert_eq!(text.chars().nth(3).unwrap().bidi_class(), BidiClass::LeftToRight);
    assert!(text.chars().nth(3).unwrap().is_ltr());
    assert!(!text.chars().nth(3).unwrap().is_rtl());
    let bidi_info = BidiInfo::new(text, None);
    assert_eq!(bidi_info.paragraphs.len(), 1);
    let para = &bidi_info.paragraphs[0];
    assert_eq!(para.level.number(), 1);
    assert_eq!(para.level.is_rtl(), true);
    let line = para.range.clone();
    let display = bidi_info.reorder_line(para, line);
    assert_eq!(
        display,
        concat![
            "a",
            "b",
            "c",
            "ג",
            "ב",
            "א",
        ]
    );
    // Case
    assert_eq!(is_cased('A'), true);
    assert_eq!(is_cased('א'), false);
    // Normalization
    assert_eq!(compose('A', '\u{030A}'), Some('Å'));
    let s = "ÅΩ";
    let c = s.nfc().collect::<String>();
    assert_eq!(c, "ÅΩ");
    // Segmentation
    assert_eq!(
        Graphemes::new("a\u{310}e\u{301}o\u{308}\u{332}").collect::<Vec<&str>>(),
        &["a\u{310}", "e\u{301}", "o\u{308}\u{332}"]
    );
    assert_eq!(
        Graphemes::new("a\r\nb🇺🇳🇮🇨").collect::<Vec<&str>>(),
        &["a", "\r\n", "b", "🇺🇳", "🇮🇨"]
    );
    assert_eq!(
        GraphemeIndices::new("a̐éö̲\r\n").collect::<Vec<(usize, &str)>>(),
        &[(0, "a̐"), (3, "é"), (6, "ö̲"), (11, "\r\n")]
    );
    assert_eq!(
        Words::new(
            "The quick (\"brown\") fox can't jump 32.3 feet, right?",
            |s: &&str| s.chars().any(is_alphanumeric),
        ).collect::<Vec<&str>>(),
        &["The", "quick", "brown", "fox", "can't", "jump", "32.3", "feet", "right"]
    );
    assert_eq!(
        WordBounds::new("The quick (\"brown\")  fox").collect::<Vec<&str>>(),
        &["The", " ", "quick", " ", "(", "\"", "brown", "\"", ")", " ", " ", "fox"]
    );
    assert_eq!(
        WordBoundIndices::new("Brr, it's 29.3°F!").collect::<Vec<(usize, &str)>>(),
        &[
            (0, "Brr"),
            (3, ","),
            (4, " "),
            (5, "it's"),
            (9, " "),
            (10, "29.3"),
            (14, "°"),
            (16, "F"),
            (17, "!")
        ]
    );
}
您可以在examples和tests目录下找到更多示例。[更多将在UNIC扩展时添加...]。
许可证
许可协议之一
- Apache许可证,版本2.0(LICENSE-APACHE或https://apache.ac.cn/licenses/LICENSE-2.0)
- MIT许可证(LICENSE-MIT或https://open-source.org.cn/licenses/MIT)
任选其一。
贡献
除非您明确表示,否则任何您有意提交以包含在作品中的贡献,如Apache-2.0许可证中定义的,应如上所述双重许可,不附加任何额外条款或条件。
行为准则
UNIC项目遵循
