【问题标题】:Why String.endsWith and String.startWith are not consistent? [duplicate]为什么 String.endsWith 和 String.startsWith 不一致? [复制]
【发布时间】:2017-08-04 20:21:56
【问题描述】:

我有以下测试用例,只有第一个断言通过。为什么?

@Test
public void test() {
    String i1 = "i";
    String i2 = "İ".toLowerCase();

    System.out.println((int)i1.charAt(0)); // 105
    System.out.println((int)i2.charAt(0)); // 105

    assertTrue(i2.startsWith(i1));

    assertTrue(i2.endsWith(i1));
    assertTrue(i1.endsWith(i2));
    assertTrue(i1.startsWith(i2));
}

回复后更新

我正在尝试以不区分大小写的方式使用 startsWithendsWith,这样,下面的表达式应该返回 true。

"ALİ".toLowerCase().endsWith("i");

我猜C#Java 是不同的。

【问题讨论】:

  • 你能不能改变你的问题,这样你就不用toLowerCase()了? toLowerCase() 输出的字符是什么?
  • 请查看我的更新printlns
  • 现在尝试打印i1.length()i2.length()
  • OK 长度不同 :) 我再次更新了我的问题。
  • toLowerCase 不接受字符串作为参数,也不返回布尔值,因此无法计算为真。

标签: java string character-encoding locale


【解决方案1】:

这是因为小写İ(“拉丁大写字母 i with dot above") 在英文语言环境中变成两个字符:“latin small letter i”和“combining dot above”。

这解释了为什么它以i 开头,但不以i 结尾(而是以组合变音符号结尾)。

在土耳其语言环境中,根据土耳其语言学规则,小写 İ 简单地变为“拉丁小写字母 i”,因此您的代码可以正常工作。

这里有一个测试程序可以帮助弄清楚发生了什么:

class Test {
  public static void main(String[] args) {
    char[] foo = args[0].toLowerCase().toCharArray();
    System.out.print("Lowercase " + args[0] + " has " + foo.length + " chars: ");
    for(int i=0; i<foo.length; i++) System.out.print("0x" + Integer.toString((int)foo[i], 16) + " ");
    System.out.println();
  }
}

这是我们在配置为英语的系统上运行它时得到的结果:

$ LC_ALL=en_US.utf8 java Test "İ"
Lowercase İ has 2 chars: 0x69 0x307

这是我们在为土耳其语配置的系统上运行它时得到的结果:

$ LC_ALL=tr_TR.utf8 java Test "İ"
Lowercase İ has 1 chars: 0x69

这甚至是 String.toLowerCase(Locale) 的 API 文档使用的特定示例,您可以使用该方法在特定语言环境中获取小写版本,而不是系统默认语言环境。

【讨论】:

    【解决方案2】:

    执行toLowerCase()函数后,字符串长度为2而不是1;该字符的小写版本由两个字符表示:

    000> "İ".length()
    ===> 1
    000> "İ".toLowerCase().length()
    ===> 2
    

    其小写表示的第一个字符是小写拉丁文i,而第二个字符是变音符号:

    000> "İ".toLowerCase().charAt(0)
    ===> i
    000> "İ".toLowerCase().charAt(1)
    ===> ̇
    

    所以小写字符串确实“以”i开头,但不以它结尾。

    【讨论】:

      【解决方案3】:

      İ是Unicode字符'LATIN CAPITAL LETTER I WITH DOT ABOVE' (U+0130),是一个长度为1的Java字符串。

      "İ".toLowerCase() 返回一个长度为 2 的 Java 字符串:

      那是因为没有'LATIN SMALL LETTER I WITH DOT ABOVE' 这样的字符。它在 Unicode 中不存在。

      【讨论】:

        【解决方案4】:

        你的测试失败了,因为你使用了错误的方法......

        String i2 = "İ" 是 i 的土耳其大写形式,如果您不提供转换的语言环境,则该方法将失败

        使用语言环境可能会有所帮助:)

        public static void main(String[] args) {
        
            String i1 = "i";
            String i2 = "İ".toLowerCase(Locale.forLanguageTag("tr-TR"));
        
            System.out.println((int)i1.charAt(0)); // 105
            System.out.println((int)i2.charAt(0)); // 105
        
            System.out.println(i2.startsWith(i1));
            System.out.println(i2.endsWith(i1));
            System.out.println(i1.endsWith(i2));
            System.out.println(i1.startsWith(i2));
        } 
        

        输出将是

        105

        105

        是的

        是的

        是的

        是的

        【讨论】:

        • 如果我不知道语言环境怎么办?
        猜你喜欢
        • 2013-10-20
        • 2019-02-23
        • 1970-01-01
        • 1970-01-01
        • 2019-07-06
        • 2014-07-05
        • 2020-05-23
        • 2011-06-29
        相关资源
        最近更新 更多