【问题标题】:Java: Why String.compareIgnoreCase() uses both Character.toUpperCase() and Character.toLowerCase()? [duplicate]Java:为什么 String.compareIgnoreCase() 同时使用 Character.toUpperCase() 和 Character.toLowerCase()? [复制]
【发布时间】:2016-08-22 16:03:01
【问题描述】:

String类的compareToIgnoreCase方法是使用下面sn-p中的方法实现的(jdk1.8.0_45)。

我。为什么Character.toUpperCase(char)Character.toLowerCase(char) 都用于比较?它们中的任何一个都不足以达到比较的目的吗?

二。为什么s1.toLowerCase().compare(s2.toLowerCase()) 不用于实现compareToIgnoreCase? - 我理解相同的逻辑可以以不同的方式实现。但是,我仍然想知道是否有特定的理由选择其中一个。

    public int compare(String s1, String s2) {
        int n1 = s1.length();
        int n2 = s2.length();
        int min = Math.min(n1, n2);
        for (int i = 0; i < min; i++) {
            char c1 = s1.charAt(i);
            char c2 = s2.charAt(i);
            if (c1 != c2) {
                c1 = Character.toUpperCase(c1);
                c2 = Character.toUpperCase(c2);
                if (c1 != c2) {
                    c1 = Character.toLowerCase(c1);
                    c2 = Character.toLowerCase(c2);
                    if (c1 != c2) {
                        // No overflow because of numeric promotion
                        return c1 - c2;
                    }
                }
            }
        }
        return n1 - n2;
    }

【问题讨论】:

  • s1.toLowerCase().compare(s2.toLowerCase()) 需要创建两个新的 String 对象。实际的实现不会创建额外的对象。
  • 我猜那里有一些特别奇怪的 Unicode 角落案例。
  • stackoverflow.com/a/16083264/3788176 建议“在土耳其语言环境中有两个不同的大写“i”字母”。
  • @AndyTurner 不过也有对应的小写“i”s。
  • 我认为这是链接问题的副本,和/或链接问题是 (stackoverflow.com/questions/15518731/…) 的副本。无论如何,关键点已经在别处进行了总结。

标签: java


【解决方案1】:

这是一个使用土耳其语 i 的示例:

System.out.println(Character.toUpperCase('i') == Character.toUpperCase('İ'));
System.out.println(Character.toLowerCase('i') == Character.toLowerCase('İ'));

第一行打印false;第二个trueIdeone demo.

【讨论】:

    【解决方案2】:

    有些语言的特殊字符可以转换为大写或小写字符(或字符序列)。

    所以对于这种特殊字符,只使用一种情况可能会有一些问题。

    例如,德语中的字符Eszett ß 被转换为大写的SS。来自维基百科:

    eszett 这个名字来源于两个字母 S 和 Z,因为它们在德语中的发音。它的Unicode编码是U+00DF

    因此,如果仅使用较低的比较,则将 groß 与 Gross 相比会产生失败。


    @chrylis 这里是一个工作示例

        System.out.println("ß".toUpperCase().equals("SS"));  // True
        System.out.println("ß".toLowerCase().equals("ss"));  // false
    

    感谢@chrylis 的评论,我做了一些额外的测试,发现 String 类可能有错误:

        System.out.println("ß".toUpperCase().equals("SS"));  // True
        System.out.println("ß".toLowerCase().equals("ss"));  // false
    
        but
    
        System.out.println("ß".equalsIgnoreCase("SS"));  // False
        System.out.println("ß".equalsIgnoreCase("ss"));  // False
    

    因此,至少有一种情况,如果手动将两个字符串都转换为大写,则两个字符串相等,但如果忽略大小写进行比较,则不相等。

    【讨论】:

    • 该特定情况在 Java 中不起作用,因为 SS 是两个字符。
    • 由于上面的比较是按字符进行的,ß不会和'SS'比较。因此,只有当两个字符都是“ß”时,上述相等条件才会成立。在上述情况下会产生怎样的影响?
    【解决方案3】:

    从 Character 类文档中,在 toUpperCase 和 toLowerCase 方法中声明:

    Note that Character.isUpperCase(Character.toUpperCase(ch)) does not
    always return true for some ranges of characters, particularly those 
    that are symbols or ideographs. (Similar for toLowerCase)
    

    由于比较中可能存在异常情况,因此他们会检查两种情况,以尽可能提供最准确的响应。

    【讨论】:

      猜你喜欢
      • 2012-12-06
      • 2018-06-01
      • 2021-05-23
      • 2011-01-08
      • 1970-01-01
      • 2015-01-28
      • 1970-01-01
      • 2013-05-28
      • 1970-01-01
      相关资源
      最近更新 更多