3 个版本 (破坏性)
0.3.0 | 2023 年 8 月 27 日 |
---|---|
0.2.0 | 2023 年 8 月 27 日 |
0.1.0 | 2023 年 8 月 19 日 |
793 在 算法 中
每月 47 次下载
在 srgn 中使用
27KB
214 行
Decompound
分割(分解)复合词到其组成部分。适用于任何语言,您提供构成(单个)词的规则。算法是 Unicode 兼容的。
在构建时缩小现有词典很有用。
最佳文档查看方式是通过 docs.rs(但请注意,这些文档与版本相关,可能不与主干分支同步)。
用法
用法非常简单。只有一个(免费)的感兴趣的功能,decompound
。它的特色是一个闭包参数,决定一个 单个 词是否有效。由于这可以非常动态且语言特定,因此这个决定留给用户。
use decompound::{decompound, DecompositionOptions};
let is_valid_single_word = |w: &str| ["bed", "room"].contains(&w);
assert_eq!(
decompound(
"bedroom",
&is_valid_single_word,
DecompositionOptions::empty(),
).unwrap(),
vec!["bed", "room"]
);
有效性检查的候选者可以是简单的字典查找(例如,使用 std::collections::HashSet
、phf
、有限状态转换器、二分搜索 等),或您选择的任何复杂算法。
配置
配置通过 位域 以 DecompositionOptions
的形式公开。它提供了更复杂的使用案例,可以自由组合。实用性主要取决于手头的自然语言。例如,德语可能需要
use decompound::{decompound, DecompositionError, DecompositionOptions};
let is_valid_single_word = |w: &str| ["Rüben", "Knollen", "Küche"].contains(&w);
assert_eq!(
decompound(
"Rübenknollen-Küche",
&is_valid_single_word,
// Wouldn't find anything without titlecasing `knollen` to `Knollen`,
// and splitting on hyphens.
DecompositionOptions::SPLIT_HYPHENATED
| DecompositionOptions::TRY_TITLECASE_SUFFIX
).unwrap(),
vec!["Rüben", "Knollen", "Küche"]
);
有关更多选项和示例,请参阅 DecompositionOptions
的文档。
失败模式
如果单词无法分解,则返回 DecompositionError
。
use decompound::{decompound, DecompositionError, DecompositionOptions};
let is_valid_single_word = |w: &str| ["water", "melon"].contains(&w);
assert_eq!(
decompound(
"snowball",
&is_valid_single_word,
DecompositionOptions::empty(),
).unwrap_err(),
DecompositionError::NothingValid
);
过度热切的验证
没有任何东西阻止你提供一个接受复合词的闭包本身。复合词(如railroad
)包含在查找字典中(而不是仅包含其词根rail
和road
),这是一个“病态”的例子。自己处理复合词正是这个库旨在减轻的事情。如果你已经有了这个功能,不想或不能放弃,那么这个库可能对你的情况不再适用(因此是“过于激进的检查”)。
尽管decompound
尽可能选择拆分,例如
use decompound::{decompound, DecompositionError, DecompositionOptions};
// Contains a compound word *and* its root words.
let is_valid_single_word = |w: &str| ["blueberry", "blue", "berry"].contains(&w);
assert_eq!(
decompound(
"blueberry",
&is_valid_single_word,
DecompositionOptions::empty(),
).unwrap(),
vec!["blue", "berry"]
);
如果词根缺失但复合词本身存在,则技术上分解失败。这种情况被视为错误,并标记为错误。这比返回长度为1的[Vec
]更方便,因为它需要在调用点进行更尴尬的错误处理。
use decompound::{decompound, DecompositionError, DecompositionOptions};
// *Only* contains a compound word, not its root words.
let is_valid_single_word = |w: &str| ["firefly"].contains(&w);
assert_eq!(
decompound(
"firefly",
&is_valid_single_word,
DecompositionOptions::empty(),
).unwrap_err(),
DecompositionError::SingleWord("firefly".to_string())
);
如果在这个领域中这种情况不是错误,请对此变体进行匹配(这个库本身也这样做)。
动机
这个库的实现很简单,你完全可以自己编写。
但是有一个问题。如前所述,这个库可以帮助你将复合词的检查从静态(一个固定字典)移动到运行时(decompound
)。对于某些语言来说,这是绝对必要的,因为复合词的集合可能很大,或者(实际上,不是数学上)没有限制,这意味着词根可以组合成任意长度。
德语就是这样一种情况。没有字典可以涵盖所有可能的德语单词。然而,现有的字典几乎可以肯定包含一些复合词(这通常很有帮助)。当使用这样的字典和这个库来涵盖所有剩余的任意复合词时,会出现重复,字典就不再是极小的了。字典中的大多数,也许所有复合词都可以在运行时检测到(在这个过程中提供单一的真实来源)。
清理字典可能会带来显著的,也许必要的大小(内存和可执行文件)节省。对于清理,需要一个构建脚本。然而,现在正在构建的代码和构建脚本都依赖于相同的检测算法。它在哪里?
-
构建脚本不能依赖于它正在构建的内容。因此,算法不能存在于正在构建的库中。
-
将算法复制粘贴到构建脚本中的诱惑产生了。然而,如果用于清理字典的东西与运行时的操作不同步,就会产生错误。可维护性受到影响。因此,复制算法不是一种选择。
-
目前(2023-08-19),除了另一个库之外,没有地方可以放置检查,这个库位于构建脚本和实际代码之外。那就是这个库。它提供了
- 一个非循环的构建图,
- 算法的单一真实来源,
- 使用任何字典,无需任何外部预处理(原始字典可以保留)。
开发
库包含一个伴随的二进制文件。它可以通过cargo run
简单地访问。这允许在本地运行此库,前提是有stdin上的单词列表。例如
$ sudo apt update && sudo apt install --yes wngerman
$ cat /usr/share/dict/ngerman | cargo run -- --try-titlecase-suffix --split-hyphenated 'Affengruppen-Überfall' 2>/dev/null
Affen
Gruppen
Überfall
依赖项
~485KB