#unicode-normalization #unicode #normalization #unicode-text

unic-ucd-normal

UNIC — Unicode 字符数据库 — 正规化属性

10 个版本 (破坏性更新)

0.9.0 2019年3月3日
0.8.0 2019年1月2日
0.7.0 2018年2月7日
0.6.0 2017年9月22日
0.1.2 2017年6月20日

#282国际化 (i18n)

Download history 1003/week @ 2024-03-15 1529/week @ 2024-03-22 1392/week @ 2024-03-29 1532/week @ 2024-04-05 1721/week @ 2024-04-12 1712/week @ 2024-04-19 1308/week @ 2024-04-26 1597/week @ 2024-05-03 1672/week @ 2024-05-10 1234/week @ 2024-05-17 1577/week @ 2024-05-24 2090/week @ 2024-05-31 1357/week @ 2024-06-07 2006/week @ 2024-06-14 2664/week @ 2024-06-21 1532/week @ 2024-06-28

每月下载量 7,876
用于 31 个 Crates (3 个直接使用)

MIT/Apache

115KB
1.5K SLoC

UNIC:Rust 的 Unicode 和国际化 Crates

UNIC-logo

Travis Rust-1.45+ Unicode-10.0.0 Release Crates.io Documentation Gitter

https://github.com/open-i18n/rust-unic

UNIC 是一个用于开发 Rust 编程语言组件的项目,以提供高质量且易于使用的 Unicode 和国际化数据和算法的 Crates。换句话说,它就像是 Rust 中的 ICU,完全用 Rust 编写,主要在 安全 模式下,但在可能的情况下也受益于 不安全 模式的性能提升。

请参阅 UNIC 更新日志 以获取最新发布的详细信息。

项目目标

UNIC 的目标是提供对 Unicode 和国际化所有级别功能的访问,从 Unicode 字符属性开始,到 Unicode 文本处理的 Unicode 算法,以及基于 Unicode Common Locale 数据库 (CLDR) 的更高级(基于地区的)过程。

根据需要实现其他标准和最佳实践,如 IETF RFC,例如 Unicode/CLDR 组件或普遍需求。

项目状态

目前 UNIC 正在快速发展:API 在 master 分支上频繁更新,每个 0.x 版本之间都可能出现 API 破坏。请参阅 公开问题 以了解更改计划。

我们预计将在 2018 年发布 1.0 版本,之后维护稳定的 API,在最初的几年里,每年可能有一到两次 API 更新。

设计目标

  1. UNIC 的主要目标是提供通过易于使用的 API 实现的可靠功能。因此,添加的新组件可能不是针对性能进行了很好的优化,但将具有足够的测试以证明符合标准,并具有示例以展示用户如何使用它们来解决常见需求。

  2. UNIC组件的下一个主要目标是性能以及低二进制和内存占用。特别是,优化ASCII和其他常见情况的运行时,将鼓励适应而无需担心减慢常规开发过程。

  3. 在尽可能的范围内,组件将提供一致的数据和算法。跨组件测试用于捕获实现之间的任何不一致,而不会减慢开发过程。

组件及其组织

UNIC 组件 采用层次结构组织,从 unic 根开始,包含 主要组件。每个主要组件反过来可以包含一些 次要组件

主要组件的API是为库的最终用户设计的,并预期将提供详尽的文档,并附带代码示例。

与主要组件相反,次要组件充当更高级别数据和服务提供者,其API预计将更高效,并可能提供多种访问数据的方式。

UNIC超级组件

unic 超级组件是一个UNIC(主要)组件的集合,提供了一种轻松访问所有功能的方法,当所有或许多组件都需要时,而不是逐个导入组件。这个组件确保所有导入的组件在算法和数据上都是兼容的。

主要的代码示例和跨组件集成测试都是在这个组件下实现的。

主要组件

  • unic-char:Unicode字符工具。 Crates.io

  • unic-ucd:Unicode字符数据库(《UAX#44》)。 Crates.io

  • unic-bidi:Unicode双向算法(《UAX#9》)。 Crates.io

  • unic-normal:Unicode标准化形式(《UAX#15》)。 Crates.io

  • unic-segment:Unicode文本分割算法(《UAX#29》)。 Crates.io

  • unic-idna:Unicode IDNA兼容处理(《UTS#46》)。 Crates.io

  • unic-emoji:Unicode表情符号(《UTS#51》)。 Crates.io

应用

代码组织:合并仓库

拥有合并仓库的这些组件的一些原因包括

  • 更快的发展。实现新的 Unicode/i18n 组件通常需要依赖其他(底层)组件,而这些组件反过来可能需要调整——暴露新的 API、修复错误等,这些可以在更少的循环和更短的时间内开发和测试。

  • 实现完整性。对其他组件的多个依赖意味着这些组件在某种程度上需要相互一致。许多 Unicode 算法由更小的算法组成,假设算法的所有部分都使用相同的 Unicode 数据版本。违反这一假设可能导致不一致和难以捕捉的错误。在合并仓库中,可以在开发过程中以及跨组件(集成)测试中达到更好的完整性。

  • 按需付费。小型组件(基本 crates),仅交叉依赖它们所需要的内容,允许用户仅将他们项目中所消耗的内容引入。

  • 共享引导。大量扩展 Unicode/i18n 功能依赖于将源 Unicode/区域数据转换为目标编程语言的格式化格式。在合并仓库中,维护这些引导工具、扩展覆盖范围以及使用更高效的数据结构变得更加容易。

文档

如何使用 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, ""), (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, "!")
        ]
    );
}

您可以在 examplestests 目录下找到更多示例。(随着 UNIC 的扩展,还将添加更多...)

许可证

根据以下任一许可证授权

任选其一。

贡献

除非您明确表示,否则根据 Apache-2.0 许可证定义的,任何有意提交以包含在您的工作中的贡献,都应按上述方式双许可,不附加任何额外条款或条件。

行为准则

UNIC 项目遵循 《Rust 行为准则》。您可以在 CODE_OF_CONDUCT.md 或在线 https://rust-lang.net.cn/conduct.html 上找到其副本。


lib.rs:

UNIC — UCD — 正规化

unic:Rust 的 Unicode 和国际化 Crates 的组成部分。

Unicode 字符属性用于组合和分解。

extern crate unic_ucd_normal;

use unic_ucd_normal::compose;

fn main() {
    assert_eq!(compose('A','\u{30a}'), Some('Å'));
}

依赖项