2个不稳定版本
0.9.0 | 2019年3月3日 |
---|---|
0.8.0 | 2019年1月2日 |
1827 在 文本处理 中排名
每月下载量 804
在 22 个仓库中使用 (直接使用 3 个)
58KB
786 行
UNIC:为Rust语言提供Unicode和国际化的组件
https://github.com/open-i18n/rust-unic
UNIC 是一个旨在为Rust编程语言开发组件的项目,以提供高质量的、易于使用的Unicode和国际化和算法的crates。换句话说,它就像是Rust版的 ICU,完全用Rust编写,主要在 safe 模式下,但在可能的情况下也会受益于 unsafe 模式的性能提升。
请参阅 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-normal
:Unicode 正规化形式(UAX#15)。 -
unic-segment
:Unicode 文本分段算法(UAX#29)。 -
unic-emoji
:Unicode 表情符号(UTS#51)。
应用
unic-cli
:UNIC 命令行工具
代码组织:组合存储库
以下是一些将组件组合成一个存储库的原因
-
更快地开发。实现新的 Unicode/i18n 组件通常需要依赖其他(较低级别)组件,而这些组件反过来可能需要进行调整——暴露新的 API、修复错误等,这些都可以在更少的周期和更短的时间内进行开发、测试和审查。
-
实现完整性。多个组件对其他组件的依赖意味着组件在某种程度上需要相互一致。许多由较小部分组成的Unicode算法假设算法的所有部分都在使用相同的Unicode数据版本。违反这个假设可能会导致不一致和难以捕捉的bug。在联合仓库中,在开发过程中以及在跨组件(集成)测试中,都有可能达到更好的完整性。
-
按需付费。小型组件(基本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或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 - UCD - 区块
是unic
的一部分:Rust的Unicode和国际化crate。
Unicode字符数据库(UCD)代码块的访问器