28

假设有两个 Java String 对象:

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

那么对于<my string>表达式的每个值,是不是真的

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

评估为true?

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

4

3 回答 3

44

令人惊讶的是它没有

来自toLowerCase的 Java 文档

使用给定语言环境的规则将此字符串中的所有字符转换为小写。大小写映射基于 Character 类指定的 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)
    }
}
于 2010-03-01T16:38:25.763 回答
4

首先,我想指出,我绝对同意@codaddict 的(目前评分最高的)答案。

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

这不是一个正式的证明,但这段代码为我运行而没有到达内部if(在 Ubuntu 上使用 JDK 1.6.0 Update 16):

编辑:这是一些处理语言环境的更新代码:

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-01T17:05:36.190 回答
2

还要记住 toUpperCase() 也不保留长度。示例:对于德语语言环境,“straße”变为“STRASSE”。因此,如果您使用区分大小写的字符串并且需要存储某些内容的索引,那么您或多或少会搞砸。

于 2011-02-09T12:00:05.630 回答