2010-03-01 72 views
27

假设两个Java String对象:Java的toLowerCase()是否保留原始字符串长度?

String str = "<my string>"; 
String strLower = str.toLowerCase(); 

是它,然后真的为<my string>表达

str.length() == strLower.length() 

计算为每true价值?

那么,String.toLowerCase()保留原始字符串长度的任何值的字符串?

回答

41

令人惊讶的是它确实不是 !!

toLowerCase

Java文档转换都在这个字符串中的字符来降低使用给定Locale的规则情况。大小写映射严重依赖于Unicode规范的字符数据。 由于大小写映射并不总是1:1字符映射,因此生成的字符串可能与原始字符串的长度不同。

举例:所有的

package com.stackoverflow.q2357315; 

import java.util.Locale; 

public class Test { 
    public static void main(String[] args) throws Exception { 
     Locale.setDefault(new Locale("lt")); 
     String s = "\u00cc"; 
     System.out.println(s + " (" + s.length() + ")"); // Ì (1) 
     s = s.toLowerCase(); 
     System.out.println(s + " (" + s.length() + ")"); // i̇̀ (3) 
    } 
} 
+5

你能举出一些例子吗?我知道几个例子,这些例子会使大写变体的大小与小写大小不同,例如, 'ß'会变成'SS',但不是相反的。 – BalusC 2010-03-01 16:42:25

+10

+1:javadocs - 如此接近,但迄今为止...... – MicSim 2010-03-01 16:43:24

+7

@BususC:关于在区域设置AZ,LT和TR中组合字符有一些奇特的规则,请参阅'java/lang/ConditionalSpecialCasing.java'。例如''\ u00cc“.toLowerCase(new Locale(”lt“)).length()== 3' – axtavt 2010-03-01 17:58:32

4

首先,我想指出的是,我绝对@codaddict的(目前最高评级)答案达成一致。

但我想做一个实验,所以这里是:

这不是一个正式的证明,但是这个代码跑了我而没有达到 if(使用JDK 1.6.0内部更新16在Ubuntu):

编辑:下面是一些更新的代码来处理语言环境,以及:

import java.util.Locale; 

public class ToLowerTester { 
    public final Locale locale; 

    public ToLowerTester(final Locale locale) { 
     this.locale = locale; 
    } 

    public String findFirstStrangeTwoLetterCombination() { 
     char[] b = new char[2]; 
     for (char c1 = 0; c1 < Character.MAX_VALUE; c1++) { 
      b[0] = c1; 
      for (char c2 = 0; c2 < Character.MAX_VALUE; c2++) { 
       b[1] = c2; 
       final String string = new String(b); 
       String lower = string.toLowerCase(locale); 
       if (string.length() != lower.length()) { 
        return string; 
       } 
      } 
     } 
     return null; 
    } 
    public static void main(final String[] args) { 
     Locale[] locales; 
     if (args.length != 0) { 
      locales = new Locale[args.length]; 
      for (int i=0; i<args.length; i++) { 
       locales[i] = new Locale(args[i]); 
      } 
     } else { 
      locales = Locale.getAvailableLocales(); 
     } 
     for (Locale locale : locales) { 
      System.out.println("Testing " + locale + "..."); 
      String result = new ToLowerTester(locale).findFirstStrangeTwoLetterCombination(); 
      if (result != null) { 
       String lower = result.toLowerCase(locale); 
       System.out.println("Found strange two letter combination for locale " 
        + locale + ": <" + result + "> (" + result.length() + ") -> <" 
        + lower + "> (" + lower.length() + ")"); 
      } 
     } 
    } 
} 

运行该代码与地区名米在接受的答案中提到将会列举一些例子。不带参数运行它将尝试所有可用的语言环境(并花费相当长的一段时间!)。

这并不是很广泛,因为从理论上讲可能有多字符字符串的行为不同,但它是一个很好的第一个近似值。

另请注意,以这种方式生成的许多双字符组合可能是无效的UTF-16,所以在此代码中没有爆炸的事实只能归咎于Java中非常健壮的String API。

最后但并非最不重要的:即使对于Java的当前实现这种假设是正确的,一旦未来的Java版本实现未来版本的Unicode标准,即可以轻易改变它,其中新字符的规则可能引入情况这不再成立。

因此依赖于这仍然是一个非常糟糕的主意。

+3

你应该知道你写的代码是依赖于默认语言环境的。不明显,但讨厌。 – 2010-03-01 17:50:40

2

还要记住,toUpperCase()也不保留长度。例如:德语区域的“straße”变为“STRASSE”。所以,如果你正在处理区分大小写的字符串,并且你需要存储索引以获得某些东西,那么你或多或少就会陷入困境。

+0

由于Straße和Strasse都是正确的拼写(忽略了它们应该有一个大写字母S因为它们是名词),所以我认为它会产生一个有趣的副作用,即大写和后面都会导致不同的字符串?你试过了吗? – Fredrik 2011-02-09 12:10:40

相关问题