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

Meh*_*taş 3 java string locale character-encoding

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

@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));
}
Run Code Online (Sandbox Code Playgroud)

回复后更新

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

"AL?".toLowerCase().endsWith("i");
Run Code Online (Sandbox Code Playgroud)

我想C#Java有所不同.

tha*_*guy 6

发生这种情况是因为?英语语言环境中的小写字母("带上面的点的拉丁语大写字母i")变成了两个字符:"拉丁小写字母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();
  }
}
Run Code Online (Sandbox Code Playgroud)

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

$ LC_ALL=en_US.utf8 java Test "?"
Lowercase ? has 2 chars: 0x69 0x307
Run Code Online (Sandbox Code Playgroud)

以下是我们在为土耳其语配置的系统上运行时获得的内容:

$ LC_ALL=tr_TR.utf8 java Test "?"
Lowercase ? has 1 chars: 0x69
Run Code Online (Sandbox Code Playgroud)

这甚至是String文档用于String.toLowerCase(Locale)的特定示例,这是您可以用来获取特定区域设置中的小写版本而不是系统默认区域设置的方法.