我在哪里可以找到一组特定的排序规则来比较字符串的相等性?

Posted

技术标签:

【中文标题】我在哪里可以找到一组特定的排序规则来比较字符串的相等性?【英文标题】:Where can I find a specific set of collation rules for equality comparison of strings? 【发布时间】:2012-01-13 11:10:10 【问题描述】:

我们都知道,使用 String 的 equals() 方法进行相等比较会失败得很惨。相反,应该使用Collator,如下所示:

// we need to detect User Interface locale somehow
Locale uiLocale = Locale.forLanguageTag("da-DK");
// Setting up collator object
Collator collator = Collator.getInstance(uiLocale);
collator.setStrength(Collator.SECONDARY);
collator.setDecomposition(Collator.CANONICAL_DECOMPOSITION);
// strings for equality testing
String test1 = "USA lover Grækenland støtte";
String test2 = "USA lover graekenland støtte";
boolean result = collator.equals(test1, test2);

现在,此代码有效,即结果为真除非 uiLocale 设置为丹麦语。在这种情况下,它将产生错误。我当然明白为什么会发生这种情况:这只是因为equals方法是这样实现的:

return compare(s1, s2) == Collator.Equal;

此方法调用用于排序并检查字符串是否相同的方法。它们不是,因为丹麦特定的排序规则要求将 æ 排序在(如果我正确理解比较方法的结果)ae 之后。但是,这些字符串真的是相同的,具有这种优势,大小写差异和兼容性字符(这就是它的名称)应该被视为平等。

要解决此问题,可以使用 RuleBasedCollator 和适用于相等情况的特定规则集。 最后的问题是:有谁知道我在哪里可以获得这样的特定规则(不仅适用于丹麦语,也适用于其他语言),以便将兼容性字符、连字等视为平等(CLDRchart 确实似乎不包含此类或我搜索失败)?

或者我想在这里做一些愚蠢的事情,我真的应该简单地使用UCA 进行相等比较(请提供任何代码示例)?

【问题讨论】:

Strings equals() 完全按照它应该做的事情,并且将单词与某些语言中的等效拼写进行比较不是其中的一部分,所以我发现说它惨遭失败是一种误导。 @Stefan:问题是它不是。例如,对于包含重音字符或变音符号(à 或 ä)的字符串,如果其中一个字符串使用规范分解,它将返回 false。拼写可能相同,没关系。更糟糕的结果会给你 equalsIgnoreCase() - 不会识别像 sharp s 或 final sigma 这样的案例变体。那只是因为这些方法使用了不适合国际字符串的二进制比较。 关键字是规范分解。这是一种(自然)语言功能,与字符串表示无关,实际上在大多数情况下,您希望将它们作为字符串区别对待。我同意你对 equalsIgnoreCase 的看法,因为它模糊了字符串之间的界限,该字符串只是语言/区域设置中字符和单词的容器。 你试过全分解吗? "我们都知道使用String的equals()方法进行相等比较会惨败。".你凭什么可以作出这样的断言? “平等”的共同定义是平等的条件。当然“USA lover Graekenland støtte”不等于“USA lover graekenland støtte”,java 与否?你在问什么? 【参考方案1】:

我找不到任何现有的丹麦语 Collat​​or;丹麦语语言环境的内置语言应该是正确的。我不确定你认为ae 应该与æ 排序的假设是否成立,特别是由于丹麦语中的某些外来词(例如"aerofobi")(我不是说丹麦语的人,尽管我会说瑞典语)。

但是,如果您想将它们排序在一起,似乎有两种方法可以做到这一点,具体取决于您所处的环境。在某些情况下,仅替换字符可能是合适的:

String str = "USA lover graekenland støtte";
String sortStr = str.replace("ae", "æ");

另一个可能更好的选项是您指定的选项;使用RuleBasedCollator。使用 javadocs 中的示例,这非常简单:

String danish = "< a, A < b, B < c, C < d, D < e, E < f, F < g, G < h, H < i, I" +
                "< j, J < k, K < l, L < m, M < n, N < o, O < p, P < q, Q < r, R" +
                "< s, S < t, T < u, U < v, V < w, W < x, X < y, Y < z, Z" +
                "< \u00E6 = ae," +       // Latin letter ae
                "  \u00C6 = AE " +       // Latin letter AE
                "< \u00F8, \u00D8" +     // Latin letter o & O with stroke
                "< \u00E5 = a\u030A," +  // Latin letter a with ring above
                "  \u00C5 = A\u030A;" +  // Latin letter A with ring above
                "  aa, AA";
RuleBasedCollator danishCollator = new RuleBasedCollator(danish);

然后您可以使用:

String test1 = "USA lover Grækenland støtte";
String test2 = "USA lover Graekenland støtte";         // note capital 'G'
boolean result = danishCollator.equals(test1, test2);  // true

如果您认为默认整理器不正确,您不妨report a bug。 (之前有similar bugs)。

更新:我用印刷的丹麦语百科全书检查了这一点。确实有以“ae”开头的单词(主要是外语单词;例如“有氧运动”)以“æ”开头的单词排序(因此不等于)。因此,尽管我明白为什么在许多情况下您会希望将它们平等对待,但严格来说并非如此。

【讨论】:

我不是在问排序。丹麦的排序规则是正确的。老实说,这甚至与丹麦规则无关,只是平等比较规则。目前还没有这样的公开规则。 对,如果你使用 Collat​​or 和提供的集合,你的 'ae' 和 'æ' 是相等的。【参考方案2】:

获取特定语言环境规则的一种方法是使用 getRules 函数。但是,在 android 中,此函数返回一个空字符串。

    RuleBasedCollator collTemp = (RuleBasedCollator) Collator
            .getInstance(Locale.US);
    String usRules = collTemp.getRules();


    //Save rules in a file
    String rulesPath = "C:\\projects\\droid\\rules.txt";
    BufferedWriter out = new BufferedWriter
            (new OutputStreamWriter(new FileOutputStream(rulesPath),"UTF-16"));
    out.write(usRules);
    out.close();

这些规则与比较函数使用的规则相同。

if (collTemp.compare(target, str) < 0)

注意:我尝试将 JDK 桌面应用程序字符串中的规则插入 Android RuleBasedCollat​​or 构造函数,但我得到 U_INVALID_FORMAT_ERROR(仅限 Android)。所以我仍在试图弄清楚如何在Android中获得美国规则。

【讨论】:

以上是关于我在哪里可以找到一组特定的排序规则来比较字符串的相等性?的主要内容,如果未能解决你的问题,请参考以下文章

当我在Mysql存储Base64数据时,崩了!!

我在哪里可以找到 scipy 中的 mad(平均绝对偏差)?

我在哪里可以找到实施的耐心差异?

如何通过比较字符串出现的位置来对字符串列表进行排序?

我在哪里可以找到 AWS 服务的区域字符串列表,例如:s3

数据库、表、列排序规则的区别