Подтвердить что ты не робот

Сохраняет ли Java toLowerCase() исходную длину строки?

Предположим, что два объекта Java String:

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

Правда ли, что для каждого значения <my string> выражение

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

оценивается как true?

Итак, String.toLowerCase() сохраняет исходную длину строки для любого значения String?

4b9b3361

Ответ 1

Удивительно, что он не!!

Из документов Java toLowerCase

Преобразует все символы в этой строке в нижний регистр, используя правила данного языка. Отображения случаев в значительной степени зависят от символьных данных спецификации Юникода. Так как отображения событий не всегда являются отображениями 1:1 char, результирующая строка может быть другой длины, чем исходная строка.

Пример:

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)
    }
}

Ответ 2

Прежде всего, я хотел бы указать, что я абсолютно согласен с (в настоящее время самым высоким) ответом @codaddict.

Но я хотел сделать эксперимент, так вот он:

Это не формальное доказательство, но этот код работал у меня, не достигнув внутри if (используя JDK 1.6.0 Update 16 на Ubuntu):

Изменить: Здесь приведен обновленный код, который также обрабатывает 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() + ")");
            }
        }
    }
}

Запуск этого кода с именами локалей, указанными в принятом ответе, напечатает несколько примеров. Запуск без аргумента будет проверять все доступные локали (и займет довольно много времени!).

Это не обширно, потому что теоретически могут быть многосимвольные строки, которые ведут себя по-другому, но это хорошее первое приближение.

Также обратите внимание, что многие из двухсимвольных комбинаций, созданных таким образом, вероятно, являются недопустимыми UTF-16, поэтому тот факт, что ничего не взрывается в этом коде, можно обвинить только в очень надежном String API в Java.

И последнее, но не менее важное: даже если предположение верно для текущей реализации Java, которое может легко измениться после того, как будущие версии Java реализуют будущие версии стандарта Unicode, в которых правила для новых символов могут вводить ситуации, когда это больше не выполняется.

Так что в зависимости от этого все еще довольно плохая идея.

Ответ 3

Также помните, что toUpperCase() также не сохраняет длину. Пример: "straße" становится "STRASSE" для немецкого языка. Таким образом, вы более или менее ввернуты, если работаете с строками, чувствительными к регистру, и вам нужно сохранить индекс для чего-то.