#compound #word #dictionary #detection

bin+lib decompound

将复合词分解为其组成部分。适用于任何语言,您提供构成(单个)词的规则。

3 个版本 (破坏性)

0.3.0 2023 年 8 月 27 日
0.2.0 2023 年 8 月 27 日
0.1.0 2023 年 8 月 19 日

793算法

每月 47 次下载
srgn 中使用

MIT 许可证

27KB
214

Decompound

分割(分解)复合词到其组成部分。适用于任何语言,您提供构成(单个)词的规则。算法是 Unicode 兼容的。

在构建时缩小现有词典很有用。

最佳文档查看方式是通过 docs.rs(但请注意,这些文档与版本相关,可能不与主干分支同步)。

codecovcrates

用法

用法非常简单。只有一个(免费)的感兴趣的功能,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::HashSetphf有限状态转换器二分搜索 等),或您选择的任何复杂算法。

配置

配置通过 位域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)包含在查找字典中(而不是仅包含其词根railroad),这是一个“病态”的例子。自己处理复合词正是这个库旨在减轻的事情。如果你已经有了这个功能,不想或不能放弃,那么这个库可能对你的情况不再适用(因此是“过于激进的检查”)。

尽管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