5个稳定版本
1.2.0 | 2022年10月23日 |
---|---|
1.1.0 | 2022年9月16日 |
1.0.2 | 2022年8月31日 |
1.0.1 | 2022年8月30日 |
#224 在 文本处理 中
795,263 每月下载量
在 53 个crates中 使用 (直接使用 9 个)
1MB
79K SLoC
finl Unicode支持
该crate是为finl项目的Unicode需求设计的,但也被设计为其他软件可用的。在当前版本(1.0.x)中,提供了字符码识别、音节分割和Unicode14.0.0的支持。
概述
类别识别
使用带有categories
特征的finl_unicode
crate将向char类型添加方法以测试字符的类别或识别其类别。请参阅rustdoc以获取详细信息。
音节簇
使用带有grapheme_clusters
特征的finl_unicode
crate将扩展Peekable<CharIndices>
以具有一个next_cluster()
方法,该方法将返回迭代器中的下一个音节簇。还有通过在&str
上调用Graphemes::new(s)
得到的纯簇迭代器。我在finl中没有使用它,但使用与扩展Peekable<CharIndices>
相同的算法编写它,目的是进行基准测试。¹
为什么?
已经存在用于这些目的的crate,但分割缺少我想要的接口(即能够扩展Peekable<CharIndices>
以具有获取下一个音节簇的方法,如果存在)。我错误地假设这需要字符码识别,但实际上并不需要,但我发现我使用的crate过时了,可能已经被遗弃,并且算法效率低下,所以我写这个crate是个好事。我对我编写的代码与现有crate进行了基准测试,并发现我设法在所有这些中取得了性能提升,所以这是一个额外的加分项。
基准测试结果
所有基准测试都是使用 Criterion 生成的。您可以通过在项目目录中运行 cargo bench
来复现它们。所有结果都给出了三个数字:低/平均值/高,均来自 Criterion 的输出。平均值以 粗体 显示。
Unicode 类别
我运行了三个基准测试来比较这些 crate 的性能。日语文本基准测试读取 John Falkner 所著的《Kumogata monsho》的 Project Gutenberg 电子书,并计算其中的 Unicode 字符。捷克文本基准测试读取 Jan Stastný、Jan Lepar 和 Josef Sokol 所著的《Cítanka pro skoly obecné》的 Project Gutenberg 电子书(这是为了测试针对带有许多变音符号的拉丁字母文本)。所有字母和大小写字母都被计数。英文文本基准测试读取 Mary Wollstonecraft Shelley 所著的《Frankenstein》的 Project Gutenberg 电子书(用于与纯 ASCII 文本进行比较)。所有字母和大小写字母都被计数。源代码检查来自 neovim。同样,在样本中计数的也是字母和大小写字母。
我将其与 unicode_categories 0.1.1 进行了比较。所有时间都是以毫秒为单位。越小越好。
基准测试 | finl_unicode |
unicode_categories |
---|---|---|
日语文本 | 0.62484/0.64200/0.66311 | 15.382/15.719/16.092 |
捷克文本 | 0.18248/0.19137/0.19975 | 3.2322/3.3329/3.4435 |
捷克文本(小写) | 0.20361/0.20529/0.20724 | 1.8496/1.8742/1.9026 |
英文文本 | 0.52260/0.54461/0.56682 | 13.038/13.330/13.655 |
英文文本(小写) | 0.72885/0.74219/0.75668 | 8.3998/8.5037/8.6233 |
源代码 | 0.05544/0.05785/0.06046 | 1.6512/1.7063/1.7656 |
源代码(小写) | 0.07506/0.07673/0.07895 | 0.7285/0.7536/0.7821 |
如您所见,这是一个明显的胜利(差异在于算法的选择。《code>finl_unicode 使用两步表查找来紧凑地存储类别,而 unicode_categories
使用表的范围检查和二分搜索的组合)。
音节簇
我还将它们与 unicode_segmentation 1.9.0(unicode-rs 项目的一部分)和 bstr 1.0.0 进行了比较。比较是在来自 Unicode 测试套件的 graphemes.txt 上运行的,另外还有一些是 unicode_segmentation 基准测试套件中的语言文本。
所有时间都是以微秒为单位,越小越好。
基准测试 | finl_unicde |
unicode_segmentation |
bstr |
---|---|---|---|
Unicode 图形符号 | 130.34/133.31/137.00 | 209.51/217.50/225.53 | 337.68/354.59/372.75 |
阿拉伯文本 | 262.05/268.78/273.65 | 443.11/463.19/482.25 | 842.78/872.47/906.84 |
英文文本 | 387.88/395.08/404.00 | 527.29/552.92/586.04 | 424.73/437.04/449.23 |
印地文本 | 204.88/216.04/228.14 | 489.75/500.55/512.20 | 638.01/641.28/644.87 |
日语文本 | 181.65/190.87/202.92 | 437.98/451.51/467.17 | 855.04/880.48/904.88 |
韩文文本 | 298.19/304.42/312.47 | 813.45/844.54/880.53 | 1259.2/1304.7/1350.6 |
中文文本 | 154.55/159.33/164.22 | 284.59/293.63/306.59 | 679.67/704.13/730.46 |
俄文文本 | 300.56/312.86/327.44 | 372.59/392.12/419.40 | 783.41/838.96/896.44 |
源代码 | 424.39/443.88/463.77 | 501.16/506.81/513.27 | 513.79/531.82/551.31 |
添加一些额外的测试揭示了一些有趣的性能对比。在具有最小聚集的文本(英文和源代码)中,我的代码比 unicode_segmentation
和 bstr
(但不是特别如此)要快,而且有趣的是,在英文文本基准测试中,bstr
比 unicode_segmentation
略快,但一旦图形符号聚集变得更加普遍(阿拉伯文和印地文),我的 crate 的性能就会大幅提升。我不期望在日语中看到聚集,但日语和韩文在性能上的差异最为明显。
为什么是它?
如果您需要 no_std
(也许我会在未来的版本中涵盖这一点,但可能不会),请避免使用它。如果您需要其他聚类算法,我目前没有计划实现它们(但如果为此付费,我会这样做)。
由于我不需要 finl 的功能,因此没有与 unicode_segmentation
的 GraphemeCursor
相当的功能。不支持对图形符号进行反向迭代,也没有计划支持。
我不支持 unicode-segmentation
支持的旧版聚类算法。然而,Unicode 规范不鼓励使用旧版聚类,它只为与非常旧的 Unicode 标准版本保持向后兼容性而记录。
Unicode 版权声明
本包包含Unicode Inc.提供的数据。版权所有 © 1991–2022 Unicode, Inc. 保留所有权利。
支持
我已经将此代码以MIT/Apache许可证发布。你可以随意使用它。我不介意对finl的开发提供支持,但这不是必需的(尽管如果你是微软或谷歌,并且使用了我的代码,你当然可以在我的银行账户中投入一些美元)。我不提供任何保修或支持,但如果你想给我一些钱,我可以优先处理你的请求。
版本历史
- 1.0.0 初次发布
- 1.0.1 更改构建过程以使docs.rs文档能够构建
- 1.0.2 由于第一轮更改似乎还不够,因此进行了更多更改
- 1.1.0 添加对Unicode 15.0.0的支持,并添加了新的基准比较
- 1.2.0 允许在任何对
Peekable
迭代器进行图元聚类操作,迭代器是char
或(usize,char)
。
- 由于技术原因,迭代器扩展返回
Option<String>
而不是Option<&str>
,因此将自动表现低于返回所有图元聚类的其他实现。然而,对于finl,我无论如何都需要包含聚类的字符串的所有权值,而且由于我只偶尔需要聚类,我决定接受这种性能损失。但请参阅基准结果,以了解我在进行速度的苹果对苹果比较时显然成功地实现了一个更快的算法。 - 纯粹猜测,但我想这可能是
finl_unicode
和unicode_segmentation
之间性能差异的整个原因。然而,我尚未查看源代码以证实我的猜测。