java 如何在文本中进行排序和搜索,同时忽略所有类型的变音符号?

a5g8bdjr  于 2023-02-18  发布在  Java
关注(0)|答案(2)|浏览(95)

背景

不同的语言都有所谓的“Diacritics“,这是一种与“正常”字母以某种方式出现的特殊符号,它们可能会改变字母的发音,或者只是暗示它们应该是什么样的发音。

问题是

当使用基本方法搜索和排序字符串时,它使用字符的Unicode值,因此排序顺序可能不正确,或者搜索时找不到。
搜索应该允许我找到一个字符串在另一个字符串中的出现,不仅包括它们存在,还包括它们在哪里。
例如,如果我以法语中的字符串“Le Garçon”为例,搜索“rc”,它会在“r”的位置找到它,并以“Çs "的位置结束。如果您希望突出显示找到文本的位置,找到位置非常重要。

我所发现的

Collator和CollationKey可帮助进行排序:https://stackoverflow.com/a/75334111/878126
Normalizer可能有助于搜索,因为它会替换带有附加符号的字母:https://stackoverflow.com/a/10700023/878126
但是,这些似乎没有涵盖一些语言。例如,我知道希伯来语,在希伯来语中,它有Niqqud(相当于英语中的元音,但是可选的)符号,作为一个Unicode字符,添加在字母后面。即使符号本身显示在字母内部/周围。
https://en.wikipedia.org/wiki/Diacritic#Hebrew
在这种情况下,单词的规范化不起任何作用,因此搜索文本并对其进行排序就成了一个问题。
例如:

val regex = Pattern.compile("[\\p{InCombiningDiacriticalMarks}\\p{IsLm}\\p{IsSk}]+").toRegex()
val string = "בְּרֵאשִׁית"
val length = string.length // this is 11 and not 6 as it seems for other languages
val normalized = Normalizer.normalize(string, Normalizer.Form.NFD)
val result = normalized.replace(regex, "") // this still becomes the same exact value as on the original, instead of "בראשית"

有人告诉我(在这里),也许ICU4J library可以帮助这两个操作(搜索和排序),但我找不到这个信息。

问题

在Java/KotlinAPI中有没有更好的解决方案可以在忽略变音符号的同时进行搜索和排序?一个包含尽可能多的语言的解决方案?
ICU 4J有可能会有所帮助吗?如果有,如何帮助?我在Java/Kotlin中找不到关于如何使用ICU 4J实现此目的的信息和示例。

epggiuax

epggiuax1#

试试这个,它会将你的字符串标准化以便于搜索:

String s = "çéèïïÔé";
    s= Normalizer.normalize(s, Form.NFD).replaceAll("\\p{InCombiningDiacriticalMarks}+", "");
    System.out.println(s.toString());
js81xvg6

js81xvg62#

在你的例子中,“变音符号”在Unicode中实际上并没有被归类为变音符号,它们属于“非空格标记”Mn。
此正则表达式满足您的测试:[\\p{IsHebrew}&&\\p{IsMn}]我不懂希伯来文,所以我不知道它是否会在其他地方引起问题,或者错过希伯来文的一些其他元素。
下面是一个演示[\\p{IsHebrew}&&\\p{IsMn}]的测试:

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public class SO75476483 {

    @Test
    public void inTheBeginning() {
        var niqqud = "[\\p{IsHebrew}&&\\p{IsMn}]";
        var text = "בְּרֵאשִׁית";
        int length = text.length();
        Assertions.assertEquals(11, length);
        String actual = text.replaceAll(niqqud, "");
        Assertions.assertEquals("בראשית", actual);
    }

}

相关问题