4个版本 (破坏性)
0.9.0 | 2019年3月3日 |
---|---|
0.8.0 | 2019年1月2日 |
0.7.0 | 2018年2月7日 |
0.6.0 | 2017年9月22日 |
#125 in 文本处理
472,741 每月下载量
用于 1,047 个crate(直接使用18个)
46KB
690 行
UNIC:为Rust提供的Unicode和国际化的crate
https://github.com/open-i18n/rust-unic
UNIC 是一个开发用于Rust编程语言的组件的项目,旨在提供高质量、易于使用的Unicode和国际化的数据和算法crate。换句话说,它就像是针对Rust的ICU,完全用Rust编写,大部分在安全模式下编写,但在可能的情况下也利用了不安全模式带来的性能提升。
请参阅 UNIC变更日志 了解最新发布详情。
项目目标
UNIC的目标是提供对所有Unicode和国际化的功能级别的访问,从Unicode字符属性开始,到用于处理文本的Unicode算法,再到基于Unicode通用区域数据存储库(CLDR)的高级(基于区域设置)过程。
根据需要,还实现了其他标准和最佳实践,如IETF RFC。
项目状态
目前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 数据版本。违反这一假设可能导致不一致性和难以捕捉的错误。在合并仓库中,在开发期间以及在跨组件(集成)测试中,都有可能达到更好的完整性。
-
按需付费。小型组件(基本 crates),只跨依赖它们所需的内容,允许用户只将他们项目中消耗的内容引入。
-
共享启动。大量扩展 Unicode/i18n 功能依赖于将源 Unicode/locale 数据转换为目标编程语言的格式化格式。在合并仓库中,维护这些启动工具、扩展覆盖范围以及使用更高效的数据结构更为容易。
文档
- 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 License,版本 2.0(《LICENSE-APACHE》或 http://www.apache.org/licenses/LICENSE-2.0)
- MIT 许可证(《LICENSE-MIT》或 http://opensource.org/licenses/MIT)
由您选择。
贡献
除非您明确声明,否则根据 Apache-2.0 许可证定义,您有意提交的任何贡献,包括但不限于在作品中包含的,应作为上述双重许可,不附加任何额外条款或条件。
行为准则
UNIC 项目遵循 Rust 行为准则。您可以在 CODE_OF_CONDUCT.md 中找到其副本,或在线查看 https://www.rust-lang.net.cn/conduct.html。
lib.rs
:
UNIC —— Unicode 字符工具 —— 字符属性
是 unic
: Rust 的 Unicode 和国际化 Crates 的组件。
字符属性分类、合约和构建宏。