2010-03-01 64 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

相關問題