这个混合字符串如何在 unicode 单词边界上拆分

问题描述

考虑字符串 "abc를"。根据unicode的demo implementation of word segmentation,这个字符串应该分成两个词,"abc""를"。然而,词边界检测的 3 个不同 Rust 实现(regexunic-segmentunicode-segmentationall 不同意,并将该字符串分组为一个词。哪种行为是正确的?

作为后续,如果分组行为是正确的,那么以仍然主要尊重单词边界的方式扫描此字符串以查找搜索词“abc”的好方法是什么(目的是检查字符串翻译)。我想匹配 "abc를" 之类的东西,但不匹配 abcdef 之类的东西。

解决方法

我不太确定分词演示是否应该被视为基本事实,即使它是在官方网站上。例如,它认为 "abc를" ("abc\uB97C") 是两个单独的词,但认为 "abc를" ("abc\u1105\u1173\u11af") 是一个,即使前者分解为后者。

词边界的想法并不是一成不变的。 Unicode 有一个 Word Boundary 规范,它概述了应该和不应该发生断字的地方。但是,它有一个广泛的注释部分用于详细说明其他案例(重点是我的):

不可能提供一套统一的规则来解决跨语言的所有问题或处理给定语言中的所有歧义情况。本附件中提出的规范的目标是提供一个可行的默认值;量身定制的实现可以更复杂。

对于泰语、老挝语、高棉语、缅甸语和其他通常不在单词之间使用空格的脚本,一个好的实现不应该依赖于默认的单词边界规范。它应该使用更复杂的机制,这也是换行所需要的。日文和中文等表意文字则更为复杂。如果 Hangul 文本没有空格,同样适用。然而,在缺乏更复杂的机制的情况下,本附件中指定的规则提供了一个明确定义的默认值。

...

我的理解是,您列出的 crate 是在没有进一步上下文分析的情况下遵循规范的。为什么演示不同意我不能说,但它可能是尝试实现这些边缘情况之一。


为了解决您的具体问题,我建议使用 Regex\b 来匹配单词边界。不幸的是,这遵循相同的 unicode 规则,不会将 "를" 视为一个新词。然而,这个正则表达式实现提供了一个 escape hatch 来回退到 ascii 行为。只需使用 (?-u:\b) 来匹配非 unicode 边界:

use regex::Regex;

fn main() {
    let pattern = Regex::new("(?-u:\\b)abc(?-u:\\b)").unwrap();
    println!("{:?}",pattern.find("some abcdef abc를 sentence"));
}

您可以在 playground 上自己运行它来测试您的案例,看看这是否适合您。