为什么String.endsWith和String.startWith不一致?

时间:2017-08-04 20:21:57

标签: java string character-encoding locale

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

@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会有所不同。

4 个答案:

答案 0 :(得分:6)

这是因为小写İ("拉丁语大写字母 我在上面的点")在英语语言环境中变成了两个字符:"拉丁语小写字母i"和"结合上面的点"。

这解释了为什么它以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文档使用的特定示例,您可以使用该方法在特定区域设置中获取小写版本,而不是系统默认区域设置。

答案 1 :(得分:3)

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

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

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

答案 2 :(得分:3)

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

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

小写字母表中的第一个字符是小写拉丁语i,而第二个字符是变音符号:

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

所以小写字符串 &#34;以&#34;开头i,但它并没有以此结束。

答案 3 :(得分:1)

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

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