假設兩個Java String對象:Java的toLowerCase()是否保留原始字符串長度?
String str = "<my string>";
String strLower = str.toLowerCase();
是它,然後真的爲<my string>
表達
str.length() == strLower.length()
計算爲每true
價值?
那麼,String.toLowerCase()
保留原始字符串長度的任何值的字符串?
假設兩個Java String對象:Java的toLowerCase()是否保留原始字符串長度?
String str = "<my string>";
String strLower = str.toLowerCase();
是它,然後真的爲<my string>
表達
str.length() == strLower.length()
計算爲每true
價值?
那麼,String.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)
}
}
首先,我想指出的是,我絕對@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標準,即可以輕易改變它,其中新字符的規則可能引入情況這不再成立。
因此依賴於這仍然是一個非常糟糕的主意。
你應該知道你寫的代碼是依賴於默認語言環境的。不明顯,但討厭。 – 2010-03-01 17:50:40
還要記住,toUpperCase()也不保留長度。例如:德語區域的「straße」變爲「STRASSE」。所以,如果你正在處理區分大小寫的字符串,並且你需要存儲索引以獲得某些東西,那麼你或多或少就會陷入困境。
由於Straße和Strasse都是正確的拼寫(忽略了它們應該有一個大寫字母S因爲它們是名詞),所以我認爲它會產生一個有趣的副作用,即大寫和後面都會導致不同的字符串?你試過了嗎? – Fredrik 2011-02-09 12:10:40
你能舉出一些例子嗎?我知道幾個例子,這些例子會使大寫變體的大小與小寫大小不同,例如, 'ß'會變成'SS',但不是相反的。 – BalusC 2010-03-01 16:42:25
+1:javadocs - 如此接近,但迄今爲止...... – MicSim 2010-03-01 16:43:24
@BususC:關於在區域設置AZ,LT和TR中組合字符有一些奇特的規則,請參閱'java/lang/ConditionalSpecialCasing.java'。例如''\ u00cc「.toLowerCase(new Locale(」lt「)).length()== 3' – axtavt 2010-03-01 17:58:32