为什么String的endsWith和startsWith方法不一致?

3
我有以下测试用例,但只有第一个断言通过。为什么?
@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 来说是不同的。


1
你能否修改你的问题,不要使用 toLowerCase()toLowerCase() 方法输出什么字符? - 4castle
请查看我的更新,附带 println - Mehmet Ataş
现在尝试打印 i1.length()i2.length() - Pshemo
长度不同 :) 我又更新了我的问题。 - Mehmet Ataş
1
toLowerCase 不接受字符串作为参数,也不返回布尔值,因此它不能评估为 true。 - nbrooks
4个回答

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();
  }
}

当我们在配置为英语的系统上运行它时,我们将得到以下结果:

$ 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

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

3

3
执行toLowerCase()函数后,字符串长度变为2而不是1;该字符的小写版本由两个字符表示:
000> "İ".length()
===> 1
000> "İ".toLowerCase().length()
===> 2

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

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

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

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

true

true

true

true


如果我不知道本地化是什么怎么办? - Mehmet Ataş

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接