2 つの Java String オブジェクトを想定します。
String str = "<my string>";
String strLower = str.toLowerCase();
それでは<my string>
、式のすべての値に対して
str.length() == strLower.length()
true
?に評価されます。
では、String.toLowerCase()
文字列の任意の値に対して元の文字列の長さを保持しますか?
2 つの Java String オブジェクトを想定します。
String str = "<my string>";
String strLower = str.toLowerCase();
それでは<my string>
、式のすべての値に対して
str.length() == strLower.length()
true
?に評価されます。
では、String.toLowerCase()
文字列の任意の値に対して元の文字列の長さを保持しますか?
意外とありません!!
toLowerCaseのJavaドキュメントから
指定された Locale の規則を使用して、この String 内のすべての文字を小文字に変換します。ケース マッピングは、Character クラスで指定された Unicode 標準バージョンに基づいています。ケース マッピングは常に 1:1 char マッピングであるとは限らないため、結果の String は元の String とは異なる長さになる場合があります。
例:
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
(Ubuntu で JDK 1.6.0 Update 16 を使用して) 内部に到達することなく実行されました。
編集: Locales も処理する更新されたコードを次に示します。
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() + ")");
}
}
}
}
受け入れられた回答に記載されているロケール名でそのコードを実行すると、いくつかの例が出力されます。引数なしで実行すると、利用可能なすべてのロケールが試されます (かなり時間がかかります!)。
理論的には動作が異なる複数文字の文字列が存在する可能性があるため、広範囲ではありませんが、最初の概算としては適切です。
また、この方法で生成された 2 文字の組み合わせの多くはおそらく無効な UTF-16 であることに注意してください。したがって、このコードで何も爆発しないという事実は、Java の非常に堅牢な String API のせいにしかできません。
最後になりましたが、大事なことを言い忘れましたが、Java の現在の実装に仮定が当てはまるとしても、Java の将来のバージョンが Unicode 標準の将来のバージョンを実装すると、それは簡単に変わる可能性があります。が当てはまります。
したがって、これに依存することは依然としてかなり悪い考えです。
また、 toUpperCase() も長さを保持しないことに注意してください。例: ドイツ語ロケールの場合、「straße」は「STRASSE」になります。したがって、大文字と小文字を区別する文字列を操作していて、何かのインデックスを保存する必要がある場合は、多かれ少なかれ困惑します。